diff --git a/firmware/Makefile b/firmware/Makefile new file mode 100644 index 000000000000..c6c1ab1fe26f --- /dev/null +++ b/firmware/Makefile @@ -0,0 +1,7 @@ +obj-m += firmware-upd.o + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean \ No newline at end of file diff --git a/firmware/firmware-upd.c b/firmware/firmware-upd.c new file mode 100644 index 000000000000..40500b993075 --- /dev/null +++ b/firmware/firmware-upd.c @@ -0,0 +1,161 @@ +/* + * firmware-upd.c + * + * A Linux kernel module for managing firmware updates. + * Copyright (C) 2024 Rusin Danilo (VoltagedDebunked) + * + * This module fetches firmware from Linux kernel repositories or specified URLs, + * verifies checksums using CRC32, and writes updates to device memory. It uses + * the Linux firmware API for requesting and managing firmware images. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_FIRMWARE_NAME 64 +#define MAX_FIRMWARE_URL 256 +#define DEVICE_MEMORY_START 0x80000000 +#define FIRMWARE_DIR "/lib/firmware" + +// Structure to represent a firmware package +struct firmware_package { + char name[MAX_FIRMWARE_NAME]; // Name of the firmware + char version[MAX_FIRMWARE_NAME]; // Version of the firmware + char url[MAX_FIRMWARE_URL]; // URL for fetching the firmware + u32 checksum; // Checksum for verifying firmware integrity +}; + +// Array to hold the firmware packages and count of packages +static struct firmware_package *packages; +static size_t package_count; + +// Function to write firmware data to the device memory +static void write_firmware_to_device(const char *firmware_data, size_t size, struct device *dev) { + void __iomem *device_mem = ioremap(DEVICE_MEMORY_START, size); // Map device memory + if (!device_mem) { + pr_err("Failed to map device memory\n"); // Log error if mapping fails + return; + } + memcpy_toio(device_mem, firmware_data, size); // Copy firmware data to device memory + iounmap(device_mem); // Unmap device memory +} + +// Function to verify the firmware's checksum using CRC32 +static bool verify_firmware_checksum(const char *firmware_data, size_t size, u32 expected_checksum) { + u32 checksum = crc32(0, firmware_data, size); // Calculate the checksum + return checksum == expected_checksum; // Return true if it matches the expected checksum +} + +// Function to fetch available firmware updates +static int fetch_firmware_updates(void) { + package_count = 20; // Set the total number of firmware packages to fetch + packages = kmalloc_array(package_count, sizeof(struct firmware_package), GFP_KERNEL); // Allocate memory for firmware packages + if (!packages) { + return -ENOMEM; // Return error if memory allocation fails + } + + // Define a list of firmware packages with names, versions, and checksums + const char *firmware_list[][3] = { + {"iwlwifi-ty-a0-xx.ucode", "1.0.0", "0x12345678"}, + {"b43/ucode5.fw", "1.0.0", "0x23456789"}, + {"ast/ast1500.fw", "1.0.0", "0x34567890"}, + {"ath10k/QCA6174/hw1.0/firmware-6.bin", "1.0.0", "0x45678901"}, + {"r8168-8.050.01.napi.fw", "1.0.0", "0x56789012"}, + {"mt76/mt7663.fw", "1.0.0", "0x67890123"}, + {"brcm/BCM43430A1.hcd", "1.0.0", "0x78901234"}, + {"firmware/ath9k-htc/htc_9271.fw", "1.0.0", "0x89012345"}, + {"mt7601u.bin", "1.0.0", "0x90123456"}, + {"dsp/xxxx.fw", "1.0.0", "0x01234567"}, + {"ti-connectivity/cc256x-fw.bin", "1.0.0", "0x12345678"}, + {"iwlwifi-7265D-ucode-25.ucode", "1.0.0", "0x23456789"}, + {"iwlwifi-7260-ucode-17.ucode", "1.0.0", "0x34567890"}, + {"iwlwifi-8000C-ucode-36.ucode", "1.0.0", "0x45678901"}, + {"libertas/firmware.bin", "1.0.0", "0x56789012"}, + {"b43/ucode0.fw", "1.0.0", "0x67890123"}, + {"mt7921e/firmware.bin", "1.0.0", "0x78901234"}, + {"skylake/snd_soc_skl.bin", "1.0.0", "0x89012345"}, + {"mt7925/firmware.bin", "1.0.0", "0x90123456"}, + {"aer/rx2300.fw", "1.0.0", "0x01234567"}, + {"atlantic/atlantic.fw", "1.0.0", "0x12345678"}, + }; + + // Populate the packages array with firmware details + for (size_t i = 0; i < package_count; i++) { + strncpy(packages[i].name, firmware_list[i][0], MAX_FIRMWARE_NAME); // Copy firmware name + strncpy(packages[i].version, firmware_list[i][1], MAX_FIRMWARE_NAME); // Copy firmware version + snprintf(packages[i].url, MAX_FIRMWARE_URL, "file://%s/%s", FIRMWARE_DIR, firmware_list[i][0]); // Construct URL + packages[i].checksum = simple_strtoul(firmware_list[i][2], NULL, 16); // Convert checksum from string to integer + } + + return 0; // Return success +} + +// Function to apply a firmware update to a device +static void apply_firmware_update(const struct firmware_package *package, struct device *dev) { + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, package->name, dev); // Request firmware from the kernel + if (ret) { + pr_err("Failed to request firmware: %d\n", ret); // Log error if firmware request fails + return; + } + + // Verify the firmware's checksum before writing it to the device + if (!verify_firmware_checksum(fw->data, fw->size, package->checksum)) { + pr_err("Firmware checksum verification failed\n"); // Log error if checksum verification fails + release_firmware(fw); // Release firmware resources + return; + } + + write_firmware_to_device(fw->data, fw->size, dev); // Write verified firmware to device memory + release_firmware(fw); // Release firmware resources +} + +// Initialization function for the firmware update module +static int __init firmware_update_init(void) { + struct device *dev = NULL; // TODO: Replace with actual device pointer. + int ret; + + ret = fetch_firmware_updates(); // Fetch available firmware updates + if (ret) { + pr_err("Failed to fetch firmware updates\n"); // Log error if fetching fails + return ret; // Return error code + } + + // Iterate through each package and apply updates + for (size_t i = 0; i < package_count; i++) { + apply_firmware_update(&packages[i], dev); // Apply the firmware update + } + + kfree(packages); // Free allocated memory for packages + return 0; // Return success +} + +// Exit function for the firmware update module +static void __exit firmware_update_exit(void) { + pr_info("Firmware update module exiting\n"); // Log message on exit +} + +// Register the initialization and exit functions with the kernel +module_init(firmware_update_init); +module_exit(firmware_update_exit); + +// Module metadata +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Rusin Danilo (VoltagedDebunked)"); +MODULE_DESCRIPTION("Firmware update tool for Linux kernel"); \ No newline at end of file