From dd1b8a106fd9ef5388da8d03af15a3bcfa4ba0b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20S=C3=B6ntgen?= Date: Fri, 7 Jul 2023 11:46:39 +0200 Subject: [PATCH] drivers/wifi: perform multi-staged construction Since the wireless LAN driver is actually a 'Libc::Component' due to its incorporation of the 'wpa_spplicant' application, we have to intercept its construction because we have to initialize the Lx_kit environment before any static ctors are executed. Most Linux initcalls are implemented as ctors that will be otherwise implicitly executed before the controll is given to us in 'Libc::Component::construct'. Issue #4927. --- repos/dde_linux/lib/mk/vfs_wifi.mk | 9 -- repos/dde_linux/run/nic_router_uplinks.run | 2 +- repos/dde_linux/src/drivers/wifi/README | 25 +++- repos/dde_linux/src/drivers/wifi/main.cc | 47 ++++++- repos/dde_linux/src/lib/vfs/wifi/vfs.cc | 87 ------------- repos/dde_linux/src/lib/wifi/wlan.cc | 117 ++++++++++-------- .../app/sculpt_manager/runtime/wifi_drv.cc | 2 - repos/pc/recipes/src/pc_wifi_drv/content.mk | 3 +- repos/pc/run/pc_wifi.run | 2 - repos/ports/run/netperf.inc | 2 +- 10 files changed, 134 insertions(+), 162 deletions(-) delete mode 100644 repos/dde_linux/lib/mk/vfs_wifi.mk delete mode 100644 repos/dde_linux/src/lib/vfs/wifi/vfs.cc diff --git a/repos/dde_linux/lib/mk/vfs_wifi.mk b/repos/dde_linux/lib/mk/vfs_wifi.mk deleted file mode 100644 index 31ea6f23ea..0000000000 --- a/repos/dde_linux/lib/mk/vfs_wifi.mk +++ /dev/null @@ -1,9 +0,0 @@ -SRC_CC = vfs.cc - -DDE_LINUX_DIR := $(subst /src/include/lx_kit,,$(call select_from_repositories,src/include/lx_kit)) - -INC_DIR += $(DDE_LINUX_DIR)/src/include - -vpath %.cc $(REP_DIR)/src/lib/vfs/wifi - -SHARED_LIB := yes diff --git a/repos/dde_linux/run/nic_router_uplinks.run b/repos/dde_linux/run/nic_router_uplinks.run index fdb325b10e..c4f9d53ed2 100644 --- a/repos/dde_linux/run/nic_router_uplinks.run +++ b/repos/dde_linux/run/nic_router_uplinks.run @@ -114,7 +114,7 @@ install_config { - + diff --git a/repos/dde_linux/src/drivers/wifi/README b/repos/dde_linux/src/drivers/wifi/README index e583824999..6cc58346e8 100644 --- a/repos/dde_linux/src/drivers/wifi/README +++ b/repos/dde_linux/src/drivers/wifi/README @@ -19,7 +19,7 @@ can be used: ! ! ! -! +! ! ! ! @@ -47,7 +47,7 @@ snippet illustrates the use of the driver on the PinePhone: ! ! ! -! +! ! ! ! @@ -177,3 +177,24 @@ concern. However, when the driver is built without the depot, the boot image assemble-mechanism tries to include the non-existent 'wifi.lib.so' library. To prevent that from failing one way is adding a dummy file - the 'repos/pc/run/pc_wifi.run' illustrates how to do that. + +During development it might be necessary to automatically generate certain +dummy functions as is normally the case with drivers ported over from Linux. +To make the existing tooling (tool/dde_linux) work with the wifi driver it +is necessary to link the driver binary directly against the driver library +rather then stub ABI library. This is achieved by adapting the driver's +'target.mk' file. In + +!TARGET := wifi_drv +!SRC_CC := main.cc wpa.cc access_firmware.cc +!LIBS := base wifi +![…] + +'LIBS' must be changed as follows in case the PC wifi driver library is +used: + +!LIBS := base pc_wifi + +Afterwards the driver library is built by the 'drivers/wifi' target and +since it is now a direct dependency 'tool/dde_linux/create_dummies' can +by used to created the 'generated_dummies.c' file. diff --git a/repos/dde_linux/src/drivers/wifi/main.cc b/repos/dde_linux/src/drivers/wifi/main.cc index a3933e9e6d..0f7ee6f601 100644 --- a/repos/dde_linux/src/drivers/wifi/main.cc +++ b/repos/dde_linux/src/drivers/wifi/main.cc @@ -12,6 +12,8 @@ */ /* Genode includes */ +#include +#include #include #include #include @@ -31,6 +33,7 @@ using namespace Genode; + static Msg_buffer _wifi_msg_buffer; static Wifi::Frontend *_wifi_frontend = nullptr; @@ -92,6 +95,8 @@ extern void wifi_init(Genode::Env&, Genode::Blockade&); extern void wifi_set_rfkill_sigh(Genode::Signal_context_capability); +static Genode::Blockade _wpa_startup_blockade { }; + struct Main { Env &env; @@ -99,8 +104,6 @@ struct Main Constructible _wpa; Constructible _frontend; - Blockade _wpa_startup_blockade { }; - struct Request_handler : Wifi::Firmware_request_handler { Signal_handler _handler; @@ -174,8 +177,6 @@ struct Main Wifi::firmware_establish_handler(_request_handler); _wpa.construct(env, _wpa_startup_blockade); - - wifi_init(env, _wpa_startup_blockade); } }; @@ -191,6 +192,44 @@ void *wifi_get_buffer(void) } +/* + * Since the wireless LAN driver incorporates the 'wpa_supplicant', + * which itself is a libc-using application, we have to initialize + * the libc environment. Normally this initialization is performed + * by the libc (see 'src/lib/libc/component.cc') but as the various + * initcalls of the Linux kernel are registered as ctor we have to + * initialize the Lx_kit::Env before the static ctors are executed. + * As those are called prior to calling 'Libc::Component::construct', + * which is implemented by us, we pose as regular component and + * call the libc 'Component::construct' explicitly after we have + * finished our initialization (Lx_kit::Env include). + */ + +void Component::construct(Genode::Env &env) +{ + try { + Genode::Heap shared_obj_heap(env.ram(), env.rm()); + + Shared_object shared_obj(env, shared_obj_heap, "libc.lib.so", + Shared_object::BIND_LAZY, + Shared_object::DONT_KEEP); + + typedef void (*Construct_fn)(Genode::Env &); + + Construct_fn const construct_fn = + shared_obj.lookup("_ZN9Component9constructERN6Genode3EnvE"); + + /* prepare Lx_kit::Env */ + wifi_init(env, _wpa_startup_blockade); + + construct_fn(env); + } catch (... /* intentional catch-all */) { + Genode::error("could not perform multi-staged construction"); + throw; + } +} + + void Libc::Component::construct(Libc::Env &env) { static Main server(env); diff --git a/repos/dde_linux/src/lib/vfs/wifi/vfs.cc b/repos/dde_linux/src/lib/vfs/wifi/vfs.cc deleted file mode 100644 index e26c052f80..0000000000 --- a/repos/dde_linux/src/lib/vfs/wifi/vfs.cc +++ /dev/null @@ -1,87 +0,0 @@ -/* - * \brief Minimal VFS plugin for bringing up WLAN driver - * \author Josef Soentgen - * \date 2022-02-20 - * - * The sole purpose of this VFS plugin is to call 'Lx_kit::initialize_env' - * at the right time before 'env.exec_static_constructors' is executed. - */ - -/* - * Copyright (C) 2022 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* Genode includes */ -#include -#include - -/* DDE Linux includes */ -#include - - -namespace Vfs_wlan -{ - using namespace Vfs; - using namespace Genode; - - struct File_system; -} - -struct Vfs_wlan::File_system : Single_file_system -{ - - File_system(Vfs::Env &env, Xml_node config) - : - Single_file_system { Vfs::Node_type::CONTINUOUS_FILE, name(), - Vfs::Node_rwx::ro(), config } - { - /* - * Various ports of a DDE Linux based library rely on the - * 'env' being set before any static constructor is executed. - * So we set it here and wait for the user of the library to - * execute the constructors at the proper time. - */ - - Lx_kit::initialize(env.env()); - } - - Open_result open(char const *, unsigned, - Vfs::Vfs_handle **, - Allocator &) override - { - return OPEN_ERR_UNACCESSIBLE; - } - - Stat_result stat(char const *, Stat &) override - { - return STAT_ERR_NO_ENTRY; - } - - static char const *name() { return "wlan"; } - char const *type() override { return name(); } -}; - - -/************************** - ** VFS plugin interface ** - **************************/ - -extern "C" Vfs::File_system_factory *vfs_file_system_factory(void) -{ - struct Factory : Vfs::File_system_factory - { - Vfs::File_system *create(Vfs::Env &vfs_env, - Genode::Xml_node node) override - { - static Vfs::File_system *fs = - new (vfs_env.alloc()) Vfs_wlan::File_system(vfs_env, node); - return fs; - } - }; - - static Factory factory; - return &factory; -} diff --git a/repos/dde_linux/src/lib/wifi/wlan.cc b/repos/dde_linux/src/lib/wifi/wlan.cc index a93c430532..4a3f9c646d 100644 --- a/repos/dde_linux/src/lib/wifi/wlan.cc +++ b/repos/dde_linux/src/lib/wifi/wlan.cc @@ -69,32 +69,6 @@ struct Rfkill_helper } }; -Constructible rfkill_helper { }; - - -void Wifi::set_rfkill(bool blocked) -{ - if (!rfkill_task_struct_ptr) - return; - - lx_emul_rfkill_switch_all(blocked); - - lx_emul_task_unblock(rfkill_task_struct_ptr); - Lx_kit::env().scheduler.execute(); - - /* - * We have to open the device again after unblocking - * as otherwise we will get ENETDOWN. So unblock the uplink - * task _afterwards_ because there we call * 'dev_open()' - * unconditionally and that will bring the netdevice UP again. - */ - lx_emul_task_unblock(uplink_task_struct_ptr); - Lx_kit::env().scheduler.execute(); - - if (rfkill_helper.constructed()) - rfkill_helper->submit_notification(); -} - bool Wifi::rfkill_blocked(void) { @@ -194,7 +168,7 @@ struct Firmware_helper } Firmware_helper(Genode::Entrypoint &ep, - Wifi::Firmware_request_handler &request_handler) + Wifi::Firmware_request_handler &request_handler) : _response_handler { ep, *this, &Firmware_helper::_handle_response }, _request_handler { request_handler } @@ -243,27 +217,6 @@ struct Firmware_helper }; -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 */ @@ -306,8 +259,14 @@ struct Wlan genode_uplink_notify_peers(); } + Constructible rfkill_helper { }; + + Constructible firmware_helper { }; + Wlan(Env &env) : _env { env } { + Lx_kit::initialize(env); + genode_mac_address_reporter_init(env, Lx_kit::env().heap); { @@ -343,30 +302,84 @@ extern "C" void wakeup_wpa() } +static Wlan *_wlan_ptr; + + void wifi_init(Env &env, Blockade &blockade) { wpa_blockade = &blockade; static Wlan wlan(env); + _wlan_ptr = &wlan; } +/* + * Rfkill handling + */ + void Wifi::rfkill_establish_handler(Wifi::Rfkill_notification_handler &handler) { - rfkill_helper.construct(handler); + _wlan_ptr->rfkill_helper.construct(handler); } +void Wifi::set_rfkill(bool blocked) +{ + if (!rfkill_task_struct_ptr) + return; + + lx_emul_rfkill_switch_all(blocked); + + lx_emul_task_unblock(rfkill_task_struct_ptr); + Lx_kit::env().scheduler.execute(); + + /* + * We have to open the device again after unblocking + * as otherwise we will get ENETDOWN. So unblock the uplink + * task _afterwards_ because there we call * 'dev_open()' + * unconditionally and that will bring the netdevice UP again. + */ + lx_emul_task_unblock(uplink_task_struct_ptr); + Lx_kit::env().scheduler.execute(); + + if (_wlan_ptr->rfkill_helper.constructed()) + _wlan_ptr->rfkill_helper->submit_notification(); +} + + +/* + * Firmware handling + */ + void Wifi::firmware_establish_handler(Wifi::Firmware_request_handler &request_handler) { - firmware_helper.construct(Lx_kit::env().env.ep(), request_handler); + _wlan_ptr->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(); + if (_wlan_ptr->firmware_helper.constructed()) + return _wlan_ptr->firmware_helper->request(); return nullptr; } + + +size_t _wifi_probe_firmware(char const *name) +{ + if (_wlan_ptr->firmware_helper.constructed()) + return _wlan_ptr->firmware_helper->perform_probing(name); + + return 0; +} + + +int _wifi_request_firmware(char const *name, char *dst, size_t dst_len) +{ + if (_wlan_ptr->firmware_helper.constructed()) + return _wlan_ptr->firmware_helper->perform_requesting(name, dst, dst_len); + + return -1; +} 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 034ea25445..4fa7b84392 100644 --- a/repos/gems/src/app/sculpt_manager/runtime/wifi_drv.cc +++ b/repos/gems/src/app/sculpt_manager/runtime/wifi_drv.cc @@ -29,7 +29,6 @@ void Sculpt::gen_wifi_drv_start_content(Xml_generator &xml) xml.node("zero", [&] () {}); xml.node("log", [&] () {}); xml.node("null", [&] () {}); - xml.node("wifi", [&] () {}); gen_named_node(xml, "jitterentropy", "random"); gen_named_node(xml, "jitterentropy", "urandom"); }); gen_named_node(xml, "inline", "rtc", [&] () { @@ -71,7 +70,6 @@ void Sculpt::gen_wifi_drv_start_content(Xml_generator &xml) gen_parent_rom_route(xml, "libc.lib.so"); gen_parent_rom_route(xml, "libm.lib.so"); gen_parent_rom_route(xml, "vfs_jitterentropy.lib.so"); - 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"); diff --git a/repos/pc/recipes/src/pc_wifi_drv/content.mk b/repos/pc/recipes/src/pc_wifi_drv/content.mk index 92c4b6b371..4ab7f1e53d 100644 --- a/repos/pc/recipes/src/pc_wifi_drv/content.mk +++ b/repos/pc/recipes/src/pc_wifi_drv/content.mk @@ -23,7 +23,7 @@ WS_PORT_DIR := $(call port_dir,$(DDE_LINUX_REP_DIR)/ports/wpa_supplicant) LIBNL_PORT_DIR := $(call port_dir,$(DDE_LINUX_REP_DIR)/ports/libnl) DDE_LINUX_LIB_MK := \ - $(addprefix lib/mk/,libnl.inc libnl_include.mk wifi.inc vfs_wifi.mk) \ + $(addprefix lib/mk/,libnl.inc libnl_include.mk wifi.inc) \ $(foreach SPEC,x86_32 x86_64,lib/mk/spec/$(SPEC)/libnl.mk) \ $(addprefix lib/mk/,wpa_driver_nl80211.mk wpa_supplicant.mk) @@ -34,7 +34,6 @@ MIRROR_FROM_DDE_LINUX_DIR := $(DDE_LINUX_LIB_MK) \ lib/symbols/wifi \ include/wifi \ $(shell cd $(DDE_LINUX_REP_DIR); find src/lib/libnl -type f) \ - $(shell cd $(DDE_LINUX_REP_DIR); find src/lib/vfs/wifi -type f) \ $(shell cd $(DDE_LINUX_REP_DIR); find src/lib/wifi -type f) \ $(shell cd $(DDE_LINUX_REP_DIR); find src/lib/wpa_driver_nl80211 -type f) \ $(shell cd $(DDE_LINUX_REP_DIR); find src/lib/wpa_supplicant -type f) diff --git a/repos/pc/run/pc_wifi.run b/repos/pc/run/pc_wifi.run index f27498c8c5..94cb6f52cd 100644 --- a/repos/pc/run/pc_wifi.run +++ b/repos/pc/run/pc_wifi.run @@ -90,7 +90,6 @@ set build_components { server/dynamic_rom server/nic_router test/lwip/http_srv - lib/vfs_wifi lib/vfs_lwip } @@ -298,7 +297,6 @@ append config { - diff --git a/repos/ports/run/netperf.inc b/repos/ports/run/netperf.inc index 0f33ef0a82..8696db4b14 100644 --- a/repos/ports/run/netperf.inc +++ b/repos/ports/run/netperf.inc @@ -267,7 +267,7 @@ append config { - + 2018-01-01 00:01