From ea0a69287996843ec8b2b35c2775818b146fcb11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20S=C3=B6ntgen?= Date: Wed, 3 May 2023 17:34:22 +0200 Subject: [PATCH] wifi: get firmware from tar archive This commit changes the firmware handling from requesting each firmware file as a ROM module that is checked against a list of known images (including their size) to requesting each file via the local VFS of the 'wifi_drv'. This allows for using the original probing mechanism that tries to select a matching firmware version. The 'repos/dde_linux/src/drivers/wifi/README' file contains more detailed information on how to configure the driver. Issue #4861. --- repos/dde_linux/include/wifi/firmware.h | 58 ++++++ repos/dde_linux/lib/symbols/wifi | 2 + repos/dde_linux/ports/linux-firmware.hash | 2 +- repos/dde_linux/ports/linux-firmware.port | 4 +- .../recipes/raw/pc_wifi_firmware/content.mk | 19 -- repos/dde_linux/run/nic_router_uplinks.run | 4 + repos/dde_linux/src/drivers/wifi/README | 22 ++- .../src/drivers/wifi/access_firmware.cc | 77 ++++++++ .../src/drivers/wifi/access_firmware.h | 33 ++++ repos/dde_linux/src/drivers/wifi/main.cc | 77 +++++++- repos/dde_linux/src/drivers/wifi/target.mk | 2 +- repos/dde_linux/src/lib/wifi/firmware.cc | 88 ++------- repos/dde_linux/src/lib/wifi/firmware_list.h | 26 --- repos/dde_linux/src/lib/wifi/lx_emul.c | 64 +++---- repos/dde_linux/src/lib/wifi/symbol.map | 2 + repos/dde_linux/src/lib/wifi/wlan.cc | 180 ++++++++++++++++++ repos/gems/run/sculpt.run | 2 + .../app/sculpt_manager/runtime/wifi_drv.cc | 30 +-- .../recipes/raw/pc_wifi_firmware/content.mk | 24 +++ .../recipes/raw/pc_wifi_firmware/hash | 0 repos/pc/run/pc_wifi.run | 28 ++- repos/ports/run/netperf.inc | 6 +- 22 files changed, 553 insertions(+), 197 deletions(-) create mode 100644 repos/dde_linux/include/wifi/firmware.h delete mode 100644 repos/dde_linux/recipes/raw/pc_wifi_firmware/content.mk create mode 100644 repos/dde_linux/src/drivers/wifi/access_firmware.cc create mode 100644 repos/dde_linux/src/drivers/wifi/access_firmware.h delete mode 100644 repos/dde_linux/src/lib/wifi/firmware_list.h create mode 100644 repos/pc/recipes/raw/pc_wifi_firmware/content.mk rename repos/{dde_linux => pc}/recipes/raw/pc_wifi_firmware/hash (100%) diff --git a/repos/dde_linux/include/wifi/firmware.h b/repos/dde_linux/include/wifi/firmware.h new file mode 100644 index 0000000000..aa2cc365f8 --- /dev/null +++ b/repos/dde_linux/include/wifi/firmware.h @@ -0,0 +1,58 @@ +/* + * \brief Firmware access interface + * \author Josef Soentgen + * \date 2023-05-05 + */ + +/* + * Copyright (C) 2023 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _WIFI__FIRMWARE_H_ +#define _WIFI__FIRMWARE_H_ + +#include + +namespace Wifi { + + struct Firmware_request : Genode::Interface + { + enum State { INVALID, PROBING, PROBING_COMPLETE, + REQUESTING, REQUESTING_COMPLETE }; + State state { INVALID }; + bool success { false }; + + /* name of the firmware image requested by the driver */ + char const *name { nullptr }; + + /* + * Length of the firmware image in bytes used for + * arranging the memory buffer for the loaded firmware. + */ + unsigned long fw_len { 0 }; + + /* + * Pointer to and length of the memory location where + * the firmware image should be copied into to. It is + * allocated by the driver. + */ + char *dst { nullptr }; + unsigned long dst_len { 0 }; + + virtual void submit_response() = 0; + }; + + struct Firmware_request_handler : Genode::Interface + { + virtual void submit_request() = 0; + }; + + void firmware_establish_handler(Firmware_request_handler &); + Firmware_request *firmware_get_request(); + +} /* namespace Wifi */ + +#endif /* _WIFI__FIRMWARE_H_ */ diff --git a/repos/dde_linux/lib/symbols/wifi b/repos/dde_linux/lib/symbols/wifi index f543c69efd..8c52530c18 100644 --- a/repos/dde_linux/lib/symbols/wifi +++ b/repos/dde_linux/lib/symbols/wifi @@ -19,3 +19,5 @@ jiffies_64 D 0 socket_call B 1 wifi_ifindex T wifi_ifname T +_ZN4Wifi20firmware_get_requestEv T +_ZN4Wifi26firmware_establish_handlerERNS_24Firmware_request_handlerE T diff --git a/repos/dde_linux/ports/linux-firmware.hash b/repos/dde_linux/ports/linux-firmware.hash index a7ecdcbc06..6f5ff41c36 100644 --- a/repos/dde_linux/ports/linux-firmware.hash +++ b/repos/dde_linux/ports/linux-firmware.hash @@ -1 +1 @@ -a04c8eb7c80e3d17836c7c8065c5c4358af8258b +dc55c3afb4c9498364834030d33e3922addb1387 diff --git a/repos/dde_linux/ports/linux-firmware.port b/repos/dde_linux/ports/linux-firmware.port index e20ede00fc..cc139a3650 100644 --- a/repos/dde_linux/ports/linux-firmware.port +++ b/repos/dde_linux/ports/linux-firmware.port @@ -2,7 +2,7 @@ LICENSE := mixed VERSION := 1 DOWNLOADS := fw.archive -FW_REV := a3216b6e5f31996f791577ba019a58419122ace6 +FW_REV := b7b5865b749f5a321259d95e0959929789a94959 URL(fw) := https://github.com/cnuke/dde_linux_firmware/archive/$(FW_REV).tar.gz -SHA(fw) := 310be6f8fd5ba65caa92187a4c1c9c6c8ab05ba4ef4df869e8a486594286fdc7 +SHA(fw) := 0fd10961cae2582a9a3e9efca7a8d761427f215562626a221062abd001e36772 DIR(fw) := firmware diff --git a/repos/dde_linux/recipes/raw/pc_wifi_firmware/content.mk b/repos/dde_linux/recipes/raw/pc_wifi_firmware/content.mk deleted file mode 100644 index c7a47dc800..0000000000 --- a/repos/dde_linux/recipes/raw/pc_wifi_firmware/content.mk +++ /dev/null @@ -1,19 +0,0 @@ -PORT_DIR := $(call port_dir,$(REP_DIR)/ports/linux-firmware) - -content: ucode_files LICENSE.wifi_drv - - -.PHONY: ucode_files -ucode_files: - cp $(PORT_DIR)/firmware/*.bin . - cp $(PORT_DIR)/firmware/*.ucode . - cp $(PORT_DIR)/firmware/*.pnvm . - cp $(PORT_DIR)/firmware/regulatory.db . - cp $(PORT_DIR)/firmware/regulatory.db.p7s . - -LICENSE.wifi_drv: - for i in $(PORT_DIR)/firmware/LICEN*E.*; do \ - echo "$${i##*/}:" >> $@; \ - cat $$i >> $@; \ - echo >> $@; \ - done diff --git a/repos/dde_linux/run/nic_router_uplinks.run b/repos/dde_linux/run/nic_router_uplinks.run index 2b906f8d03..5d16844760 100644 --- a/repos/dde_linux/run/nic_router_uplinks.run +++ b/repos/dde_linux/run/nic_router_uplinks.run @@ -119,6 +119,9 @@ install_config { + + + @@ -128,6 +131,7 @@ install_config { + diff --git a/repos/dde_linux/src/drivers/wifi/README b/repos/dde_linux/src/drivers/wifi/README index b3c2f19aef..f1f9503b84 100644 --- a/repos/dde_linux/src/drivers/wifi/README +++ b/repos/dde_linux/src/drivers/wifi/README @@ -20,15 +20,19 @@ can be used: ! ! ! -! -! +! +! ! +! ! ! ! ! ! ! +! +! +! ! ! ! @@ -44,15 +48,19 @@ snippet illustrates the use of the driver on the PinePhone: ! ! ! -! -! +! +! ! +! ! ! ! ! ! ! +! +! +! ! ! ! @@ -65,6 +73,12 @@ Note the ROM route for the device-tree binary that is essential on ARM-based platforms. The name of the request DTB can by changed by setting the 'dtb' attribute in the config node. +Depending on the used device additional firmware images might be +required. The driver will request them by accessing the '/firmware' +directory in the driver's local VFS. It is up to the configuration +how those files are made available. In these examples they are +contained in an '.tar' archive that is request as a ROM module. + The driver will request access to the ROM module 'wifi_config' to connect to a network: diff --git a/repos/dde_linux/src/drivers/wifi/access_firmware.cc b/repos/dde_linux/src/drivers/wifi/access_firmware.cc new file mode 100644 index 0000000000..3e9e2937aa --- /dev/null +++ b/repos/dde_linux/src/drivers/wifi/access_firmware.cc @@ -0,0 +1,77 @@ +/* + * \brief Firmware I/O functions + * \author Josef Soentgen + * \date 2023-05-05 + */ + +/* + * Copyright (C) 2023 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +/* Genode includes */ +#include + +/* libc includes */ +#include +#include +#include +#include + +/* local includes */ +#include "access_firmware.h" + + +Stat_firmware_result access_firmware(char const *path) +{ + Stat_firmware_result result { false, 0 }; + + + Libc::with_libc([&] { + struct stat stat_buf { }; + int const err = ::stat(path, &stat_buf); + if (!err) { + result.success = true; + result.length = stat_buf.st_size; + } + }); + + return result; +} + + +Read_firmware_result read_firmware(char const *path, char *dst, size_t dst_len) +{ + Read_firmware_result result { false }; + + Libc::with_libc([&] { + int const fd = ::open(path, O_RDONLY); + if (fd < 0) + return; + + size_t total = 0; + size_t remain = dst_len; + do { + ssize_t const cur = ::read(fd, dst, remain); + if (cur < ssize_t(0) && errno != EINTR) + break; + if (cur == ssize_t(0)) + break; + total += cur; + dst += cur; + remain -= (size_t)cur; + + } while (total < dst_len); + + (void)close(fd); + + if (total > 0 && (size_t)total != dst_len) + return; + + result.success = true; + }); + + return result; +} diff --git a/repos/dde_linux/src/drivers/wifi/access_firmware.h b/repos/dde_linux/src/drivers/wifi/access_firmware.h new file mode 100644 index 0000000000..978a04ff0c --- /dev/null +++ b/repos/dde_linux/src/drivers/wifi/access_firmware.h @@ -0,0 +1,33 @@ +/* + * \brief Firmware I/O functions + * \author Josef Soentgen + * \date 2023-05-05 + */ + +/* + * Copyright (C) 2023 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _ACCESS_FIRMWARE_H_ +#define _ACCESS_FIRMWARE_H_ + +struct Stat_firmware_result +{ + size_t length; + bool success; +}; + +Stat_firmware_result access_firmware(char const *path); + + +struct Read_firmware_result +{ + bool success; +}; + +Read_firmware_result read_firmware(char const *path, char *dst, size_t dst_len); + +#endif /* _ACCESS_FIRMWARE_H_ */ diff --git a/repos/dde_linux/src/drivers/wifi/main.cc b/repos/dde_linux/src/drivers/wifi/main.cc index 4485a5c2dc..ed4427f7b2 100644 --- a/repos/dde_linux/src/drivers/wifi/main.cc +++ b/repos/dde_linux/src/drivers/wifi/main.cc @@ -20,11 +20,14 @@ #include #include -/* local includes */ -#include -#include -#include +/* wifi library includes */ +#include +/* local includes */ +#include "util.h" +#include "wpa.h" +#include "frontend.h" +#include "access_firmware.h" using namespace Genode; @@ -98,12 +101,78 @@ struct Main Blockade _wpa_startup_blockade { }; + struct Request_handler : Wifi::Firmware_request_handler + { + Signal_handler _handler; + + void _handle_request() + { + using Fw_path = Genode::String<128>; + using namespace Wifi; + + Firmware_request *request_ptr = firmware_get_request(); + if (!request_ptr) + return; + + Firmware_request &request = *request_ptr; + + request.success = false; + + switch (request.state) { + case Firmware_request::State::PROBING: + { + Fw_path const path { "/firmware/", request.name }; + + Stat_firmware_result const result = access_firmware(path.string()); + + request.fw_len = result.success ? result.length : 0; + request.success = result.success; + + request.submit_response(); + break; + } + case Firmware_request::State::REQUESTING: + { + Fw_path const path { "/firmware/", request.name }; + + Read_firmware_result const result = + read_firmware(path.string(), request.dst, request.dst_len); + + request.success = result.success; + + request.submit_response(); + break; + } + case Firmware_request::State::INVALID: + break; + case Firmware_request::State::PROBING_COMPLETE: + break; + case Firmware_request::State::REQUESTING_COMPLETE: + break; + } + } + + Request_handler(Genode::Entrypoint &ep) + : + _handler { ep, *this, &Request_handler::_handle_request } + { } + + void submit_request() override + { + _handler.local_submit(); + } + }; + + Request_handler _request_handler { env.ep() }; + Main(Genode::Env &env) : env(env) { _frontend.construct(env, _wifi_msg_buffer); _wifi_frontend = &*_frontend; wifi_set_rfkill_sigh(_wifi_frontend->rfkill_sigh()); + Wifi::firmware_establish_handler(_request_handler); + _wpa.construct(env, _wpa_startup_blockade); wifi_init(env, _wpa_startup_blockade); diff --git a/repos/dde_linux/src/drivers/wifi/target.mk b/repos/dde_linux/src/drivers/wifi/target.mk index 2fee96fdb4..257d6ec0b5 100644 --- a/repos/dde_linux/src/drivers/wifi/target.mk +++ b/repos/dde_linux/src/drivers/wifi/target.mk @@ -1,5 +1,5 @@ TARGET := wifi_drv -SRC_CC := main.cc wpa.cc +SRC_CC := main.cc wpa.cc access_firmware.cc LIBS := base wifi LIBS += libc LIBS += wpa_supplicant diff --git a/repos/dde_linux/src/lib/wifi/firmware.cc b/repos/dde_linux/src/lib/wifi/firmware.cc index 881c9edf6c..5b3d80e9e6 100644 --- a/repos/dde_linux/src/lib/wifi/firmware.cc +++ b/repos/dde_linux/src/lib/wifi/firmware.cc @@ -17,103 +17,41 @@ /* local includes */ #include -#include using namespace Genode; - -Firmware_list fw_list[] = { - { "regulatory.db", 4144, nullptr }, - { "regulatory.db.p7s", 1182, nullptr }, - - { "iwlwifi-1000-5.ucode", 337520, nullptr }, - { "iwlwifi-3160-17.ucode", 918268, nullptr }, - { "iwlwifi-5000-5.ucode", 340696, nullptr }, - { "iwlwifi-6000-4.ucode", 454608, nullptr }, - { "iwlwifi-6000-6.ucode", 454608, "iwlwifi-6000-4.ucode" }, - { "iwlwifi-6000g2a-6.ucode", 677296, nullptr }, - { "iwlwifi-6000g2b-6.ucode", 679436, nullptr }, - { "iwlwifi-7260-17.ucode", 1049340, nullptr }, - { "iwlwifi-7265-16.ucode", 1180412, nullptr }, - { "iwlwifi-7265D-29.ucode", 1036772, nullptr }, - { "iwlwifi-8000C-36.ucode", 2428004, nullptr }, - { "iwlwifi-8265-36.ucode", 2436632, nullptr }, - - { "iwlwifi-9000-pu-b0-jf-b0-46.ucode", 1514876, nullptr }, - { "iwlwifi-9260-th-b0-jf-b0-46.ucode", 1490376, nullptr }, - - { "iwlwifi-QuZ-a0-hr-b0-68.ucode", 1355800, nullptr }, - { "iwlwifi-QuZ-a0-hr-b0-72.ucode", 1355800, "iwlwifi-QuZ-a0-hr-b0-68.ucode" }, - - { "iwlwifi-so-a0-hr-b0-68.ucode", 1429192, nullptr }, - { "iwlwifi-so-a0-hr-b0-72.ucode", 1429192, "iwlwifi-so-a0-hr-b0-68.ucode" }, - - { "iwlwifi-so-a0-gf-a0-68.ucode", 1533812, nullptr }, - { "iwlwifi-so-a0-gf-a0-72.ucode", 1533812, "iwlwifi-so-a0-gf-a0-68.ucode" }, - { "iwlwifi-so-a0-gf-a0.pnvm", 41808, nullptr }, - - { "iwlwifi-ty-a0-gf-a0-68.ucode", 1494304, nullptr }, - { "iwlwifi-ty-a0-gf-a0-72.ucode", 1494304, "iwlwifi-ty-a0-gf-a0-68.ucode" }, - { "iwlwifi-ty-a0-gf-a0.pnvm", 41588, nullptr }, - - { "rtl8192eu_nic.bin", 31818, nullptr }, - { "rtlwifi/rtl8192eefw.bin", 31818, "rtl8192eu_nic.bin" }, - { "rtl8188efw.bin", 11216, nullptr }, - { "rtlwifi/rtl8188efw.bin", 11216, "rtl8188efw.bin" }, /* FW Power Save off */ -}; - - -size_t fw_list_len = sizeof(fw_list) / sizeof(fw_list[0]); - - /********************** ** linux/firmware.h ** **********************/ +extern size_t _wifi_probe_firmware(char const *name); +extern int _wifi_request_firmware(char const *name, char *dst, size_t dst_len); + extern "C" int lx_emul_request_firmware_nowait(const char *name, void **dest, - size_t *result, bool warn) + size_t *result, bool /* warn */) { if (!dest || !result) return -1; - /* only try to load known firmware images */ - Firmware_list *fwl = 0; - for (size_t i = 0; i < fw_list_len; i++) { - if (strcmp(name, fw_list[i].requested_name) == 0) { - fwl = &fw_list[i]; - break; - } - } - - if (!fwl ) { - if (warn) - error("firmware '", name, "' is not in the firmware white list"); + size_t const fw_size = _wifi_probe_firmware(name); + if (!fw_size) return -1; - } - - char const *fw_name = fwl->available_name - ? fwl->available_name : fwl->requested_name; - Rom_connection rom(Lx_kit::env().env, fw_name); - Dataspace_capability ds_cap = rom.dataspace(); - - if (!ds_cap.valid()) { - error("could not get firmware ROM dataspace"); - return -1; - } /* use allocator because fw is too big for slab */ - void *data = Lx_kit::env().heap.alloc(fwl->size); + char *data = (char*)Lx_kit::env().heap.alloc(fw_size); if (!data) return -1; - void const *image = Lx_kit::env().env.rm().attach(ds_cap); - memcpy(data, image, fwl->size); - Lx_kit::env().env.rm().detach(image); + if (_wifi_request_firmware(name, data, fw_size)) { + error("could not request firmware ", name); + Lx_kit::env().heap.free(data, fw_size); + return -1; + } *dest = data; - *result = fwl->size; + *result = fw_size; return 0; } diff --git a/repos/dde_linux/src/lib/wifi/firmware_list.h b/repos/dde_linux/src/lib/wifi/firmware_list.h deleted file mode 100644 index 50e960ad58..0000000000 --- a/repos/dde_linux/src/lib/wifi/firmware_list.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * \brief List for firmware images and their sizes - * \author Josef Soentgen - * \date 2014-03-26 - */ - -/* - * Copyright (C) 2014-2017 Genode Labs GmbH - * - * This file is distributed under the terms of the GNU General Public License - * version 2. - */ - -#ifndef _FIRMWARE_LIST_H_ -#define _FIRMWARE_LIST_H_ - -typedef __SIZE_TYPE__ size_t; - -struct Firmware_list -{ - char const *requested_name; - size_t size; - char const *available_name; -}; - -#endif /* _FIRMWARE_LIST_H_ */ diff --git a/repos/dde_linux/src/lib/wifi/lx_emul.c b/repos/dde_linux/src/lib/wifi/lx_emul.c index 7d2d31bcba..964a881704 100644 --- a/repos/dde_linux/src/lib/wifi/lx_emul.c +++ b/repos/dde_linux/src/lib/wifi/lx_emul.c @@ -136,34 +136,41 @@ void iput(struct inode * inode) #include -#if 0 struct firmware_work { struct work_struct work; - struct firmware const *firmware; + struct firmware *firmware; + char const *name; void *context; void (*cont)(struct firmware const *, void *); }; +extern int lx_emul_request_firmware_nowait(const char *name, void *dest, + size_t *result, bool warn); static void request_firmware_work_func(struct work_struct *work) { struct firmware_work *fw_work = container_of(work, struct firmware_work, work); + struct firmware *fw = fw_work->firmware; - fw_work->cont(fw_work->firmware, fw_work->context); + if (lx_emul_request_firmware_nowait(fw_work->name, + &fw->data, &fw->size, true)) { + /* + * Free and set to NULL here as passing NULL to + * 'cont()' triggers requesting next possible ucode + * version. + */ + kfree(fw); + fw = NULL; + } + + fw_work->cont(fw, fw_work->context); kfree(fw_work); + kfree(fw); } -#endif -extern int lx_emul_request_firmware_nowait(const char *name, void *dest, - size_t *result, bool warn); -extern void lx_emul_release_firmware(void const *data, size_t size); - -extern void rtnl_lock(void); -extern void rtnl_unlock(void); - int request_firmware_nowait(struct module * module, bool uevent, const char * name, struct device * device, gfp_t gfp, @@ -172,41 +179,15 @@ int request_firmware_nowait(struct module * module, void * context)) { struct firmware *fw = kzalloc(sizeof (struct firmware), GFP_KERNEL); -#if 0 struct firmware_work *fw_work; -#endif - bool reg_db; - if (lx_emul_request_firmware_nowait(name, &fw->data, &fw->size, true)) { - kfree(fw); - return -1; - } - - /* - * Normally we would schedule fw_work but for reasons not - * yet understood doing so will lead to a page-fault. So - * for the time being we will execute the callback directly - * and we have to make sure to manage the RTNL lock as the - * callback will grab it while we already hold it. - */ - reg_db = strcmp(name, "regulatory.db") == 0; - - if (reg_db) - rtnl_unlock(); - - cont(fw, context); - - if (reg_db) - rtnl_lock(); - return 0; - -#if 0 fw_work = kzalloc(sizeof (struct firmware_work), GFP_KERNEL); if (!fw_work) { kfree(fw); return -1; } + fw_work->name = name; fw_work->firmware = fw; fw_work->context = context; fw_work->cont = cont; @@ -215,7 +196,6 @@ int request_firmware_nowait(struct module * module, schedule_work(&fw_work->work); return 0; -#endif } @@ -246,8 +226,14 @@ int request_firmware(const struct firmware ** firmware_p, } +extern void lx_emul_release_firmware(void const *data, size_t size); + + void release_firmware(const struct firmware * fw) { + if (!fw) + return; + lx_emul_release_firmware(fw->data, fw->size); kfree(fw); } diff --git a/repos/dde_linux/src/lib/wifi/symbol.map b/repos/dde_linux/src/lib/wifi/symbol.map index 5f3600650b..6bb0855d49 100644 --- a/repos/dde_linux/src/lib/wifi/symbol.map +++ b/repos/dde_linux/src/lib/wifi/symbol.map @@ -14,6 +14,8 @@ _*wifi_*_rfkill*; _*wifi_kick_*; + _*Wifi*firmware*; + /* interface for libnl/wpa_driver_nl82011 */ wifi_if*; diff --git a/repos/dde_linux/src/lib/wifi/wlan.cc b/repos/dde_linux/src/lib/wifi/wlan.cc index d3e6d0b893..f276ce5284 100644 --- a/repos/dde_linux/src/lib/wifi/wlan.cc +++ b/repos/dde_linux/src/lib/wifi/wlan.cc @@ -27,6 +27,9 @@ #include #include +/* wifi includes */ +#include + /* local includes */ #include "lx_user.h" #include "dtb_helper.h" @@ -79,6 +82,168 @@ bool wifi_get_rfkill(void) } +/* Firmware access, move to object later */ + +struct task_struct; + +struct Firmware_helper +{ + Firmware_helper(Firmware_helper const&) = delete; + Firmware_helper & operator = (Firmware_helper const&) = delete; + + void *_waiting_task { nullptr }; + void *_calling_task { nullptr }; + + Genode::Signal_handler _response_handler; + + void _handle_response() + { + if (_calling_task) + lx_emul_task_unblock((struct task_struct*)_calling_task); + + Lx_kit::env().scheduler.schedule(); + } + + Wifi::Firmware_request_handler &_request_handler; + + struct Request : Wifi::Firmware_request + { + Genode::Signal_context &_response_handler; + + Request(Genode::Signal_context &sig_ctx) + : + _response_handler { sig_ctx } + { } + + void submit_response() override + { + switch (state) { + case Firmware_request::State::PROBING: + state = Firmware_request::State::PROBING_COMPLETE; + break; + case Firmware_request::State::REQUESTING: + state = Firmware_request::State::REQUESTING_COMPLETE; + break; + default: + return; + } + _response_handler.local_submit(); + } + }; + + using S = Wifi::Firmware_request::State; + + Request _request { _response_handler }; + + void _update_waiting_task() + { + if (_waiting_task) + if (_waiting_task != lx_emul_task_get_current()) + warning("Firmware_request: already waiting task is not current task"); + + _waiting_task = lx_emul_task_get_current(); + } + + void _submit_request_and_wait_for(Wifi::Firmware_request::State state) + { + _calling_task = lx_emul_task_get_current(); + _request_handler.submit_request(); + + do { + lx_emul_task_schedule(true); + } while (_request.state != state); + } + + void _wait_until_pending_request_finished() + { + while (_request.state != S::INVALID) { + + _update_waiting_task(); + lx_emul_task_schedule(true); + } + } + + void _wakeup_any_waiting_request() + { + _request.state = S::INVALID; + if (_waiting_task) { + lx_emul_task_unblock((struct task_struct*)_waiting_task); + _waiting_task = nullptr; + } + _calling_task = nullptr; + } + + Firmware_helper(Genode::Entrypoint &ep, + Wifi::Firmware_request_handler &request_handler) + : + _response_handler { ep, *this, &Firmware_helper::_handle_response }, + _request_handler { request_handler } + { } + + size_t perform_probing(char const *name) + { + _wait_until_pending_request_finished(); + + _request.name = name; + _request.state = S::PROBING; + _request.dst = nullptr; + _request.dst_len = 0; + + _submit_request_and_wait_for(S::PROBING_COMPLETE); + + size_t const fw_length = _request.success ? _request.fw_len : 0; + + _wakeup_any_waiting_request(); + + return fw_length; + } + + int perform_requesting(char const *name, char *dst, size_t dst_len) + { + _wait_until_pending_request_finished(); + + _request.name = name; + _request.state = S::REQUESTING; + _request.dst = dst; + _request.dst_len = dst_len; + + _submit_request_and_wait_for(S::REQUESTING_COMPLETE); + + bool const success = _request.success; + + _wakeup_any_waiting_request(); + + return success ? 0 : -1; + } + + Wifi::Firmware_request *request() + { + return &_request; + } +}; + + +Constructible firmware_helper { }; + + +size_t _wifi_probe_firmware(char const *name) +{ + if (firmware_helper.constructed()) + return firmware_helper->perform_probing(name); + + return 0; +} + + +int _wifi_request_firmware(char const *name, char *dst, size_t dst_len) +{ + if (firmware_helper.constructed()) + return firmware_helper->perform_requesting(name, dst, dst_len); + + return -1; +} + + extern "C" unsigned int wifi_ifindex(void) { /* TODO replace with actual qyery */ @@ -209,3 +374,18 @@ void wifi_set_rfkill_sigh(Signal_context_capability cap) { _rfkill_sigh_cap = cap; } + + +void Wifi::firmware_establish_handler(Wifi::Firmware_request_handler &request_handler) +{ + firmware_helper.construct(Lx_kit::env().env.ep(), request_handler); +} + + +Wifi::Firmware_request *Wifi::firmware_get_request() +{ + if (firmware_helper.constructed()) + return firmware_helper->request(); + + return nullptr; +} diff --git a/repos/gems/run/sculpt.run b/repos/gems/run/sculpt.run index 7b5f1d0d70..f87f4b97d9 100644 --- a/repos/gems/run/sculpt.run +++ b/repos/gems/run/sculpt.run @@ -158,6 +158,7 @@ proc nic_driver_routes { } { set result(pc) { + } set result(mnt_reform2) { @@ -173,6 +174,7 @@ proc nic_driver_routes { } { set result(pinephone) { + } if {[info exists result([board])]} { diff --git a/repos/gems/src/app/sculpt_manager/runtime/wifi_drv.cc b/repos/gems/src/app/sculpt_manager/runtime/wifi_drv.cc index 0d78effd44..034ea25445 100644 --- a/repos/gems/src/app/sculpt_manager/runtime/wifi_drv.cc +++ b/repos/gems/src/app/sculpt_manager/runtime/wifi_drv.cc @@ -35,6 +35,11 @@ void Sculpt::gen_wifi_drv_start_content(Xml_generator &xml) gen_named_node(xml, "inline", "rtc", [&] () { xml.append("2018-01-01 00:01"); }); + gen_named_node(xml, "dir", "firmware", [&] () { + xml.node("tar", [&] () { + xml.attribute("name", "wifi_firmware.tar"); + }); + }); }); xml.node("libc", [&] () { @@ -69,32 +74,9 @@ void Sculpt::gen_wifi_drv_start_content(Xml_generator &xml) gen_parent_rom_route(xml, "vfs_wifi.lib.so"); gen_parent_rom_route(xml, "libssl.lib.so"); gen_parent_rom_route(xml, "wifi.lib.so"); + gen_parent_rom_route(xml, "wifi_firmware.tar"); gen_parent_rom_route(xml, "wpa_driver_nl80211.lib.so"); gen_parent_rom_route(xml, "wpa_supplicant.lib.so"); - gen_parent_rom_route(xml, "iwlwifi-1000-5.ucode"); - gen_parent_rom_route(xml, "iwlwifi-3160-17.ucode"); - gen_parent_rom_route(xml, "iwlwifi-3168-17.ucode"); - gen_parent_rom_route(xml, "iwlwifi-5000-5.ucode"); - gen_parent_rom_route(xml, "iwlwifi-6000-4.ucode"); - gen_parent_rom_route(xml, "iwlwifi-6000g2a-6.ucode"); - gen_parent_rom_route(xml, "iwlwifi-6000g2b-6.ucode"); - gen_parent_rom_route(xml, "iwlwifi-7260-17.ucode"); - gen_parent_rom_route(xml, "iwlwifi-7265-17.ucode"); - gen_parent_rom_route(xml, "iwlwifi-7265D-29.ucode"); - gen_parent_rom_route(xml, "iwlwifi-8000C-36.ucode"); - gen_parent_rom_route(xml, "iwlwifi-8265-36.ucode"); - gen_parent_rom_route(xml, "iwlwifi-9000-pu-b0-jf-b0-46.ucode"); - gen_parent_rom_route(xml, "iwlwifi-9260-th-b0-jf-b0-46.ucode"); - gen_parent_rom_route(xml, "iwlwifi-QuZ-a0-hr-b0-68.ucode"); - gen_parent_rom_route(xml, "iwlwifi-so-a0-hr-b0-68.ucode"); - gen_parent_rom_route(xml, "iwlwifi-so-a0-gf-a0-68.ucode"); - gen_parent_rom_route(xml, "iwlwifi-so-a0-gf-a0.pnvm"); - gen_parent_rom_route(xml, "iwlwifi-ty-a0-gf-a0-68.ucode"); - gen_parent_rom_route(xml, "iwlwifi-ty-a0-gf-a0.pnvm"); - gen_parent_rom_route(xml, "rtl8192eu_nic.bin"); - gen_parent_rom_route(xml, "rtl8188efw.bin"); - gen_parent_rom_route(xml, "regulatory.db"); - gen_parent_rom_route(xml, "regulatory.db.p7s"); gen_parent_route (xml); gen_parent_route (xml); gen_parent_route (xml); diff --git a/repos/pc/recipes/raw/pc_wifi_firmware/content.mk b/repos/pc/recipes/raw/pc_wifi_firmware/content.mk new file mode 100644 index 0000000000..b817696ade --- /dev/null +++ b/repos/pc/recipes/raw/pc_wifi_firmware/content.mk @@ -0,0 +1,24 @@ +PORT_DIR := $(call port_dir,$(GENODE_DIR)/repos/dde_linux/ports/linux-firmware) + +content: ucode_files LICENSE.wifi_drv pc_wifi_firmware.tar + + +.PHONY: ucode_files +ucode_files: + cp -R $(PORT_DIR)/firmware/rtlwifi . + cp $(PORT_DIR)/firmware/*.ucode . + cp $(PORT_DIR)/firmware/*.pnvm . + cp $(PORT_DIR)/firmware/regulatory.db . + cp $(PORT_DIR)/firmware/regulatory.db.p7s . + +LICENSE.wifi_drv: + for i in $(PORT_DIR)/firmware/LICEN*E.*; do \ + echo "$${i##*/}:" >> $@; \ + cat $$i >> $@; \ + echo >> $@; \ + done + +pc_wifi_firmware.tar: ucode_files LICENSE.wifi_drv + tar --mtime='2023-05-03 00:00Z' --remove-files \ + -cf $@ -C . *.* rtlwifi/*.* && \ + rmdir rtlwifi diff --git a/repos/dde_linux/recipes/raw/pc_wifi_firmware/hash b/repos/pc/recipes/raw/pc_wifi_firmware/hash similarity index 100% rename from repos/dde_linux/recipes/raw/pc_wifi_firmware/hash rename to repos/pc/recipes/raw/pc_wifi_firmware/hash diff --git a/repos/pc/run/pc_wifi.run b/repos/pc/run/pc_wifi.run index d374f5cfc9..92b9af7dde 100644 --- a/repos/pc/run/pc_wifi.run +++ b/repos/pc/run/pc_wifi.run @@ -1,3 +1,10 @@ +# +# Set to true in case the driver needs to be debugged to +# pull in the locally build binaries rather than the ones +# from the depot. +# +set debug_driver false + # # Configure wireless lan # @@ -80,6 +87,11 @@ set build_components { lib/vfs_lwip } +append_if $debug_driver build_components { + drivers/wifi + lib/pc_wifi +} + build $build_components # @@ -270,7 +282,7 @@ append config { - + @@ -281,6 +293,9 @@ append config { + + + @@ -291,6 +306,7 @@ append config { + @@ -299,6 +315,16 @@ append config { install_config $config +# +# Provide dummy 'wifi.lib.so' shared-object for +# boot-module assembly +# +if {$debug_driver} { +exec rm bin/wifi.lib.so +exec echo dummy > bin/wifi.lib.so +} + + # # Boot modules # diff --git a/repos/ports/run/netperf.inc b/repos/ports/run/netperf.inc index 8beba8c488..0f33ef0a82 100644 --- a/repos/ports/run/netperf.inc +++ b/repos/ports/run/netperf.inc @@ -261,7 +261,7 @@ append config { - + @@ -272,6 +272,9 @@ append config { 2018-01-01 00:01 + + + @@ -279,6 +282,7 @@ append config { +