Skip to content

Commit

Permalink
src: Firmware compression.
Browse files Browse the repository at this point in the history
Refactor the driver to call wifi_fw_funcs to get functions to load
firmware data. If CYW43_DECOMPRESS_FIRMWARE is true it will load
gzip compressed firmware using uzlib.

The driver calls cyw43_wifi_firmware_details to get details of the
firmware.

Fixes georgerobotics#4
  • Loading branch information
peterharperuk committed Nov 22, 2022
1 parent 7d3291d commit b38220b
Show file tree
Hide file tree
Showing 6 changed files with 621 additions and 111 deletions.
Binary file added firmware/43439A0-7.95.49.00.combined.gz
Binary file not shown.
146 changes: 146 additions & 0 deletions firmware/wifi_firmware.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/*
* This file is part of the cyw43-driver
*
* Copyright (C) 2019-2022 George Robotics Pty Ltd
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Any redistribution, use, or modification in source or binary form is done
* solely for personal benefit and not for any commercial purpose or for
* monetary gain.
*
* THIS SOFTWARE IS PROVIDED BY THE LICENSOR AND COPYRIGHT OWNER "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE LICENSOR OR COPYRIGHT OWNER BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software is also available for use with certain devices under different
* terms, as set out in the top level LICENSE file. For commercial licensing
* options please email contact@georgerobotics.com.au.
*/

#ifndef WIFI_FIRMWARE_H
#define WIFI_FIRMWARE_H

#if CYW43_DECOMPRESS_FIRMWARE
#include "cyw43_decompress_firmware.h"
#endif

/*!
* \brief Structure to store wifi firmware details
*/
//!\{
typedef struct cyw43_wifi_firmware_details {
size_t raw_size; ///< size in bytes of the firmware binary
const uint8_t *raw_data; ///< pointer to the firmware binary
size_t fw_size; ///< Size of the firmware in bytes
size_t clm_size; ///< Size of the clm in bytes
const uint8_t *fw_addr; ///< Pointer to the firmware in the binary
const uint8_t *clm_addr; ///< Pointer to the clm in the binary
size_t wifi_nvram_len; ///< Size of nvram data
const uint8_t *wifi_nvram_data; ///< Pointer to nvram data
} cyw43_wifi_firmware_details_t;
//!\}

/*!
* \brief Structure to hold function pointers for loading firmware
*/
//!\{
typedef struct cyw43_wifi_firmware_funcs {
int (*start)(const cyw43_wifi_firmware_details_t *fw_details); ///< start firmware loading
const uint8_t* (*get_fw_source)(const uint8_t *addr, size_t sz_in, uint8_t *buffer, size_t buffer_len); ///< get fw data
const uint8_t* (*get_nvram_source)(const uint8_t *addr, size_t sz_in, uint8_t *buffer, size_t buffer_len); ///< get nvram data
int (*get_clm)(uint8_t *dst, const uint8_t *src, uint32_t len); ///< get clm data
void (*end)(void); ///< end firmware loading
} cyw43_wifi_firmware_funcs_t;
//!\}

/*!
* \brief get firmware data from flash
*
* Loads firmware data from flash and returns a pointer to it
*
* \param addr Address of firmware data required
* \param sz_in Amount of firmware data required in bytes
* \param buffer Temporary buffer that can be used to load and return firmware data
* \param buffer_len Length of temporary buffer in bytes
* \return Requested firmware data
*/
const uint8_t *wifi_firmware_get_source_storage(const uint8_t *addr, size_t sz_in, uint8_t *buffer, size_t buffer_len);

/*!
* \brief get firmware data embedded in the elf file binary
*
* Loads firmware data from the elf file and returns a pointer to it
*
* \param addr Address of firmware data required
* \param sz_in Amount of firmware data required in bytes
* \param buffer Temporary buffer that can be used to load and return firmware data
* \param buffer_len Length of temporary buffer in bytes
* \return Requested firmware data
*/
const uint8_t *wifi_firmware_get_source_embedded(const uint8_t *addr, size_t sz_in, uint8_t *buffer, size_t buffer_len);

/*!
* \brief get clm data embedded in the elf file binary
*
* Loads clm data from the elf file binary and returns a pointer to it
*
* \param dst Destination of clm data
* \param src Source address of the clm data
* \param len Amount of data required in bytes
* \return >=0 on success or <0 on error
*/
int wifi_firmware_get_clm_embedded(uint8_t *dst, const uint8_t *src, uint32_t len);

#if CYW43_DECOMPRESS_FIRMWARE
/*!
* \brief Start firmware decompression process
*
* Prepares and allocates resources needed to decompress firmware
*
* \param fw_details Details of the firmware
* \see cyw43_wifi_firmware_details_t
* \return >=0 on success or <0 on error
*/
int wifi_firmware_start_decompress(const cyw43_wifi_firmware_details_t* fw_details);

/*!
* \brief get and decompress firmware data embedded in the elf file binary
*
* Loads firmware data from the elf file, decompressed it and returns a pointer to it
*
* \param addr Address of firmware data required
* \param sz_in Amount of firmware data required in bytes
* \param buffer Temporary buffer that can be used to load and return firmware data
* \param buffer_len Length of temporary buffer in bytes
* \return Requested firmware data
*/
const uint8_t *wifi_firmware_get_source_decompress(const uint8_t *addr, size_t sz_in, uint8_t *buffer, size_t buffer_len);

/*!
* \brief get and decompress clm data embedded in the elf file binary
*
* Loads clm data from flash, decompresses it and returns a pointer to it
*
* \param dst Destination of clm data
* \param src Source address of the clm data
* \param len Amount of data required in bytes
* \return >=0 on success or <0 on error
*/
int wifi_firmware_get_clm_decompress(uint8_t *dst, const uint8_t *src, uint32_t len);
#endif

#endif
104 changes: 104 additions & 0 deletions firmware/wifi_firmware_43439.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* This file is part of the cyw43-driver
*
* Copyright (C) 2019-2022 George Robotics Pty Ltd
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Any redistribution, use, or modification in source or binary form is done
* solely for personal benefit and not for any commercial purpose or for
* monetary gain.
*
* THIS SOFTWARE IS PROVIDED BY THE LICENSOR AND COPYRIGHT OWNER "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE LICENSOR OR COPYRIGHT OWNER BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software is also available for use with certain devices under different
* terms, as set out in the top level LICENSE file. For commercial licensing
* options please email contact@georgerobotics.com.au.
*/

#ifndef WIFI_FIRMWARE_43439_H
#define WIFI_FIRMWARE_43439_H

#include CYW43_WIFI_NVRAM_INCLUDE_FILE
#include "wifi_firmware.h"

#if CYW43_USE_SPI
#define CYW43_FW_LEN (224190) // 43439A0.bin
#define CYW43_CLM_LEN (984) // 43439_raspberrypi_picow_v5_220624.clm_blob

extern const uint8_t fw_43439A0_7_95_49_00_combined_start[];
extern const uint8_t fw_43439A0_7_95_49_00_combined_end[];
#define CYW43_FIRMWARE_START fw_43439A0_7_95_49_00_combined_start
#define CYW43_FIRMWARE_END fw_43439A0_7_95_49_00_combined_end

#elif !CYW43_USE_SPI
#define CYW43_FW_LEN (383110) // 7.45.98.50
extern const uint8_t fw_4343WA1_7_45_98_50_start[];
extern const uint8_t fw_4343WA1_7_45_98_50_end[];
#define CYW43_CLM_LEN (7222)
#define CYW43_FIRMWARE_START fw_4343WA1_7_45_98_50_start
#define CYW43_FIRMWARE_END fw_4343WA1_7_45_98_50_end
#endif

/*!
* \brief Get the firmware binary details
*
* This method returns the details of the firmware binary
*
* \param fw_details Structure to be filled with firmware details
* \see cyw43_wifi_firmware_details_t
*/
static inline void cyw43_wifi_firmware_details(cyw43_wifi_firmware_details_t *fw_details) {
fw_details->raw_size = CYW43_FIRMWARE_END - CYW43_FIRMWARE_START;
fw_details->raw_data = CYW43_FIRMWARE_START;
fw_details->fw_size = CYW43_FW_LEN;
fw_details->clm_size = CYW43_CLM_LEN,
fw_details->fw_addr = CYW43_FIRMWARE_START;
fw_details->clm_addr = CYW43_FIRMWARE_START + ((CYW43_FW_LEN + 511) & ~511);
fw_details->wifi_nvram_len = (sizeof(wifi_nvram_4343) + 63) & ~63;
fw_details->wifi_nvram_data = wifi_nvram_4343;
}

/*!
* \brief Get the functions used to load firmware
*
* This method returns pointers to functions that load firmware
*
* \return structure that contains functions that load firmware
* \see cyw43_wifi_firmware_funcs_t
*/
static inline const cyw43_wifi_firmware_funcs_t *wifi_fw_funcs(void) {
static const cyw43_wifi_firmware_funcs_t funcs = {
#if CYW43_DECOMPRESS_FIRMWARE
.start = wifi_firmware_start_decompress,
.get_fw_source = wifi_firmware_get_source_decompress,
.get_nvram_source = wifi_firmware_get_source_embedded, // not compressed
.get_clm = wifi_firmware_get_clm_decompress,
.end = cyw43_decompress_firmware_end,
#else
.start = NULL,
.get_fw_source = wifi_firmware_get_source_embedded,
.get_nvram_source = wifi_firmware_get_source_embedded,
.get_clm = wifi_firmware_get_clm_embedded,
.end = NULL,
#endif
};
return &funcs;
}

#endif
107 changes: 107 additions & 0 deletions src/cyw43_decompress_firmware.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* This file is part of the cyw43-driver
*
* Copyright (C) 2019-2022 George Robotics Pty Ltd
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Any redistribution, use, or modification in source or binary form is done
* solely for personal benefit and not for any commercial purpose or for
* monetary gain.
*
* THIS SOFTWARE IS PROVIDED BY THE LICENSOR AND COPYRIGHT OWNER "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE LICENSOR OR COPYRIGHT OWNER BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software is also available for use with certain devices under different
* terms, as set out in the top level LICENSE file. For commercial licensing
* options please email contact@georgerobotics.com.au.
*/

#include <stdio.h>
#include <string.h>

#include "pico/stdlib.h"
#include "uzlib.h"

#define DICT_SIZE 32767
typedef struct uzlib_data {
uint8_t dict[DICT_SIZE]; // todo: use smaller dictionary?
struct uzlib_uncomp state;
size_t amount_left;
} uzlib_data_t;
static uzlib_data_t *uzlib;

#define CYW43_DECOMPRESS_ERR_NO_MEM -1
#define CYW43_DECOMPRESS_ERR_BAD_HEADER -2
#define CYW43_DECOMPRESS_ERR_NO_MORE -3
#define CYW43_DECOMPRESS_ERR_DECOMPRESS -4

size_t cyw43_decompress_firmware_start(const uint8_t *raw_data, size_t raw_size)
{
uzlib_init();

uzlib = malloc(sizeof(*uzlib));
assert(uzlib);
if (!uzlib) {
return CYW43_DECOMPRESS_ERR_NO_MEM;
}

uzlib->amount_left = raw_data[raw_size - 1];
uzlib->amount_left = 256 * uzlib->amount_left + raw_data[raw_size - 2];
uzlib->amount_left = 256 * uzlib->amount_left + raw_data[raw_size - 3];
uzlib->amount_left = 256 * uzlib->amount_left + raw_data[raw_size - 4];

uzlib_uncompress_init(&uzlib->state, uzlib->dict, sizeof(uzlib->dict));

uzlib->state.source = raw_data;
uzlib->state.source_limit = raw_data + raw_size - 4;
uzlib->state.source_read_cb = NULL;

int res = uzlib_gzip_parse_header(&uzlib->state);
assert(res == TINF_OK);
if (res != TINF_OK) {
return CYW43_DECOMPRESS_ERR_BAD_HEADER;
}

return uzlib->amount_left;
}

int cyw43_decompress_firmware_next(uint8_t *buffer, size_t len)
{
assert(uzlib->amount_left > 0);
if (uzlib->amount_left <= 0) {
return CYW43_DECOMPRESS_ERR_NO_MORE;
}
const size_t chunk_len = uzlib->amount_left < len ? uzlib->amount_left : len;
uzlib->state.dest = buffer;
uzlib->state.dest_limit = uzlib->state.dest + chunk_len;
int res = uzlib_uncompress_chksum(&uzlib->state);
assert(res == TINF_OK);
if (res != TINF_OK) {
return CYW43_DECOMPRESS_ERR_DECOMPRESS;
}
uzlib->amount_left -= chunk_len;
return chunk_len;
}

void cyw43_decompress_firmware_end(void)
{
if (uzlib) {
free(uzlib);
uzlib = NULL;
}
}
Loading

0 comments on commit b38220b

Please sign in to comment.