Skip to content

Commit ee518ed

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 8876ed5 commit ee518ed

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
@@ -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,26 +1805,164 @@ 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+
}
18151869

1816-
static noinline_for_stack void
1817-
brcmf_pcie_provide_random_bytes(struct brcmf_pciedev_info *devinfo, u32 address)
1870+
static noinline_for_stack int
1871+
brcmf_pcie_add_random_seed(struct brcmf_pciedev_info *devinfo, u32 *address)
18181872
{
1873+
int err;
18191874
u8 randbuf[BRCMF_RANDOM_SEED_LENGTH];
18201875

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+
18211886
get_random_bytes(randbuf, BRCMF_RANDOM_SEED_LENGTH);
18221887
memcpy_toio(devinfo->tcm + address, randbuf, BRCMF_RANDOM_SEED_LENGTH);
1888+
1889+
return 0;
1890+
}
1891+
1892+
static int brcmf_pcie_add_signature(struct brcmf_pciedev_info *devinfo,
1893+
u32 *address, const struct firmware *fwsig)
1894+
{
1895+
int err;
1896+
struct brcmf_fw_memmap memmap;
1897+
1898+
brcmf_dbg(PCIE, "Download firmware signature\n");
1899+
1900+
memset(&memmap, 0, sizeof(memmap));
1901+
1902+
memmap.sig_end = *address;
1903+
err = brcmf_alloc_rtlv(devinfo, address, BRCMF_SIG_MAGIC, fwsig->size);
1904+
if (err)
1905+
return err;
1906+
memmap.sig_start = *address;
1907+
1908+
memmap.vstatus_end = *address;
1909+
err = brcmf_alloc_rtlv(devinfo, address, BRCMF_VSTATUS_MAGIC, BRCMF_VSTATUS_SIZE);
1910+
if (err)
1911+
return err;
1912+
memmap.vstatus_start = *address;
1913+
1914+
err = brcmf_alloc_rtlv(devinfo, address, BRCMF_MEMMAP_MAGIC, sizeof(memmap));
1915+
if (err)
1916+
return err;
1917+
1918+
memmap.fw_start = devinfo->ci->rambase;
1919+
memmap.fw_end = memmap.fw_start + devinfo->fw_size;
1920+
memmap.heap_start = memmap.fw_end + BRCMF_BL_HEAP_START_GAP;
1921+
memmap.heap_end = memmap.heap_start + BRCMF_BL_HEAP_SIZE;
1922+
1923+
if (memmap.heap_end > *address)
1924+
return -ENOMEM;
1925+
1926+
memcpy_toio(devinfo->tcm + memmap.sig_start, fwsig->data, fwsig->size);
1927+
memset_io(devinfo->tcm + memmap.vstatus_start, 0, BRCMF_VSTATUS_SIZE);
1928+
memcpy_toio(devinfo->tcm + *address, &memmap, sizeof(memmap));
1929+
1930+
err = brcmf_alloc_rtlv(devinfo, address, BRCMF_END_MAGIC, 0);
1931+
if (err)
1932+
return err;
1933+
1934+
return 0;
1935+
}
1936+
1937+
static int brcmf_pcie_populate_footers(struct brcmf_pciedev_info *devinfo,
1938+
u32 *address, const struct firmware *fwsig)
1939+
{
1940+
int err;
1941+
1942+
/* We only do this for Apple firmwares. If any other
1943+
* production firmwares are found to need this, the condition
1944+
* needs to be adjusted.
1945+
*/
1946+
if (!devinfo->otp.valid)
1947+
return 0;
1948+
1949+
err = brcmf_pcie_add_random_seed(devinfo, address);
1950+
if (err)
1951+
return err;
1952+
1953+
if (fwsig) {
1954+
err = brcmf_pcie_add_signature(devinfo, address, fwsig);
1955+
if (err)
1956+
return err;
1957+
}
1958+
1959+
return 0;
18231960
}
18241961

18251962
static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
1826-
const struct firmware *fw, void *nvram,
1827-
u32 nvram_len)
1963+
const struct firmware *fw,
1964+
const struct firmware *fwsig,
1965+
void *nvram, u32 nvram_len)
18281966
{
18291967
struct brcmf_bus *bus = dev_get_drvdata(&devinfo->pdev->dev);
18301968
u32 sharedram_addr;
@@ -1844,44 +1982,39 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
18441982
(void *)fw->data, fw->size);
18451983

18461984
resetintr = get_unaligned_le32(fw->data);
1985+
devinfo->fw_size = fw->size;
18471986
release_firmware(fw);
18481987

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

1993+
address = devinfo->ci->rambase + devinfo->ci->ramsize;
1994+
18541995
if (nvram) {
18551996
brcmf_dbg(PCIE, "Download NVRAM %s\n", devinfo->nvram_name);
1856-
address = devinfo->ci->rambase + devinfo->ci->ramsize -
1857-
nvram_len;
1997+
address -= nvram_len;
18581998
memcpy_toio(devinfo->tcm + address, nvram, nvram_len);
18591999
brcmf_fw_nvram_free(nvram);
18602000

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

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

22712405
static void brcmf_pcie_setup(struct device *dev, int ret,
22722406
struct brcmf_fw_request *fwreq)
22732407
{
2274-
const struct firmware *fw;
2408+
const struct firmware *fw, *fwsig;
22752409
void *nvram;
22762410
struct brcmf_bus *bus;
22772411
struct brcmf_pciedev *pcie_bus_dev;
@@ -2290,6 +2424,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
22902424
brcmf_pcie_attach(devinfo);
22912425

22922426
fw = fwreq->items[BRCMF_PCIE_FW_CODE].binary;
2427+
fwsig = fwreq->items[BRCMF_PCIE_FW_SIG].binary;
22932428
nvram = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.data;
22942429
nvram_len = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.len;
22952430
devinfo->clm_fw = fwreq->items[BRCMF_PCIE_FW_CLM].binary;
@@ -2300,6 +2435,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
23002435
if (ret) {
23012436
brcmf_err(bus, "Failed to get RAM info\n");
23022437
release_firmware(fw);
2438+
release_firmware(fwsig);
23032439
brcmf_fw_nvram_free(nvram);
23042440
goto fail;
23052441
}
@@ -2311,7 +2447,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
23112447
*/
23122448
brcmf_pcie_adjust_ramsize(devinfo, (u8 *)fw->data, fw->size);
23132449

2314-
ret = brcmf_pcie_download_fw_nvram(devinfo, fw, nvram, nvram_len);
2450+
ret = brcmf_pcie_download_fw_nvram(devinfo, fw, fwsig, nvram, nvram_len);
23152451
if (ret)
23162452
goto fail;
23172453

@@ -2376,6 +2512,7 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo)
23762512
{ ".txt", devinfo->nvram_name },
23772513
{ ".clm_blob", devinfo->clm_name },
23782514
{ ".txcap_blob", devinfo->txcap_name },
2515+
{ ".sig", devinfo->sig_name },
23792516
};
23802517

23812518
fwreq = brcmf_fw_alloc_request(devinfo->ci->chip, devinfo->ci->chiprev,
@@ -2386,6 +2523,8 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo)
23862523
return NULL;
23872524

23882525
fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
2526+
fwreq->items[BRCMF_PCIE_FW_SIG].type = BRCMF_FW_TYPE_BINARY;
2527+
fwreq->items[BRCMF_PCIE_FW_SIG].flags = BRCMF_FW_REQF_OPTIONAL;
23892528
fwreq->items[BRCMF_PCIE_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
23902529
fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL;
23912530
fwreq->items[BRCMF_PCIE_FW_CLM].type = BRCMF_FW_TYPE_BINARY;

0 commit comments

Comments
 (0)