Skip to content

Commit 5b9c3f6

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 a85ff11 commit 5b9c3f6

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
@@ -388,6 +388,7 @@ struct brcmf_pciedev_info {
388388
bool in_irq;
389389
struct pci_dev *pdev;
390390
char fw_name[BRCMF_FW_NAME_LEN];
391+
char sig_name[BRCMF_FW_NAME_LEN];
391392
char nvram_name[BRCMF_FW_NAME_LEN];
392393
char clm_name[BRCMF_FW_NAME_LEN];
393394
char txcap_name[BRCMF_FW_NAME_LEN];
@@ -396,8 +397,7 @@ struct brcmf_pciedev_info {
396397
const struct brcmf_pcie_reginfo *reginfo;
397398
void __iomem *regs;
398399
void __iomem *tcm;
399-
u32 ram_base;
400-
u32 ram_size;
400+
u32 fw_size;
401401
struct brcmf_chip *ci;
402402
u32 coreid;
403403
struct brcmf_pcie_shared_info shared;
@@ -1800,26 +1800,164 @@ brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo,
18001800
return 0;
18011801
}
18021802

1803-
struct brcmf_random_seed_footer {
1803+
struct brcmf_rtlv_footer {
18041804
__le32 length;
18051805
__le32 magic;
18061806
};
18071807

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

1811-
static noinline_for_stack void
1812-
brcmf_pcie_provide_random_bytes(struct brcmf_pciedev_info *devinfo, u32 address)
1865+
static noinline_for_stack int
1866+
brcmf_pcie_add_random_seed(struct brcmf_pciedev_info *devinfo, u32 *address)
18131867
{
1868+
int err;
18141869
u8 randbuf[BRCMF_RANDOM_SEED_LENGTH];
18151870

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

18201957
static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
1821-
const struct firmware *fw, void *nvram,
1822-
u32 nvram_len)
1958+
const struct firmware *fw,
1959+
const struct firmware *fwsig,
1960+
void *nvram, u32 nvram_len)
18231961
{
18241962
struct brcmf_bus *bus = dev_get_drvdata(&devinfo->pdev->dev);
18251963
u32 sharedram_addr;
@@ -1839,44 +1977,39 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
18391977
(void *)fw->data, fw->size);
18401978

18411979
resetintr = get_unaligned_le32(fw->data);
1980+
devinfo->fw_size = fw->size;
18421981
release_firmware(fw);
18431982

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

1988+
address = devinfo->ci->rambase + devinfo->ci->ramsize;
1989+
18491990
if (nvram) {
18501991
brcmf_dbg(PCIE, "Download NVRAM %s\n", devinfo->nvram_name);
1851-
address = devinfo->ci->rambase + devinfo->ci->ramsize -
1852-
nvram_len;
1992+
address -= nvram_len;
18531993
memcpy_toio(devinfo->tcm + address, nvram, nvram_len);
18541994
brcmf_fw_nvram_free(nvram);
18551995

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

2004+
release_firmware(fwsig);
2005+
2006+
/* Clear free TCM. This isn't really necessary, but it
2007+
* makes debugging memory dumps a lot easier since we
2008+
* don't get a bunch of junk filling up the free space.
2009+
*/
2010+
memset_io(devinfo->tcm + devinfo->ci->rambase + devinfo->fw_size,
2011+
0, address - devinfo->fw_size - devinfo->ci->rambase);
2012+
18802013
sharedram_addr_written = brcmf_pcie_read_ram32(devinfo,
18812014
devinfo->ci->ramsize -
18822015
4);
@@ -2262,11 +2395,12 @@ static int brcmf_pcie_read_otp(struct brcmf_pciedev_info *devinfo)
22622395
#define BRCMF_PCIE_FW_NVRAM 1
22632396
#define BRCMF_PCIE_FW_CLM 2
22642397
#define BRCMF_PCIE_FW_TXCAP 3
2398+
#define BRCMF_PCIE_FW_SIG 4
22652399

22662400
static void brcmf_pcie_setup(struct device *dev, int ret,
22672401
struct brcmf_fw_request *fwreq)
22682402
{
2269-
const struct firmware *fw;
2403+
const struct firmware *fw, *fwsig;
22702404
void *nvram;
22712405
struct brcmf_bus *bus;
22722406
struct brcmf_pciedev *pcie_bus_dev;
@@ -2285,6 +2419,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
22852419
brcmf_pcie_attach(devinfo);
22862420

22872421
fw = fwreq->items[BRCMF_PCIE_FW_CODE].binary;
2422+
fwsig = fwreq->items[BRCMF_PCIE_FW_SIG].binary;
22882423
nvram = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.data;
22892424
nvram_len = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.len;
22902425
devinfo->clm_fw = fwreq->items[BRCMF_PCIE_FW_CLM].binary;
@@ -2295,6 +2430,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
22952430
if (ret) {
22962431
brcmf_err(bus, "Failed to get RAM info\n");
22972432
release_firmware(fw);
2433+
release_firmware(fwsig);
22982434
brcmf_fw_nvram_free(nvram);
22992435
goto fail;
23002436
}
@@ -2306,7 +2442,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
23062442
*/
23072443
brcmf_pcie_adjust_ramsize(devinfo, (u8 *)fw->data, fw->size);
23082444

2309-
ret = brcmf_pcie_download_fw_nvram(devinfo, fw, nvram, nvram_len);
2445+
ret = brcmf_pcie_download_fw_nvram(devinfo, fw, fwsig, nvram, nvram_len);
23102446
if (ret)
23112447
goto fail;
23122448

@@ -2371,6 +2507,7 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo)
23712507
{ ".txt", devinfo->nvram_name },
23722508
{ ".clm_blob", devinfo->clm_name },
23732509
{ ".txcap_blob", devinfo->txcap_name },
2510+
{ ".sig", devinfo->sig_name },
23742511
};
23752512

23762513
fwreq = brcmf_fw_alloc_request(devinfo->ci->chip, devinfo->ci->chiprev,
@@ -2381,6 +2518,8 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo)
23812518
return NULL;
23822519

23832520
fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
2521+
fwreq->items[BRCMF_PCIE_FW_SIG].type = BRCMF_FW_TYPE_BINARY;
2522+
fwreq->items[BRCMF_PCIE_FW_SIG].flags = BRCMF_FW_REQF_OPTIONAL;
23842523
fwreq->items[BRCMF_PCIE_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
23852524
fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL;
23862525
fwreq->items[BRCMF_PCIE_FW_CLM].type = BRCMF_FW_TYPE_BINARY;

0 commit comments

Comments
 (0)