mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-20 09:46:20 +00:00
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.
This commit is contained in:
parent
fc24ffcdb8
commit
dd1b8a106f
@ -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
|
@ -114,7 +114,7 @@ install_config {
|
||||
<resource name="RAM" quantum="32M"/>
|
||||
<config ld_verbose="no">
|
||||
<vfs>
|
||||
<dir name="dev"> <log/> <rtc/> <null/> <wifi/>
|
||||
<dir name="dev"> <log/> <rtc/> <null/>
|
||||
<jitterentropy name="random"/>
|
||||
<jitterentropy name="urandom"/>
|
||||
</dir>
|
||||
|
@ -19,7 +19,7 @@ can be used:
|
||||
! <config>
|
||||
! <libc stdout="/dev/null" stderr="/dev/null" rtc="/dev/rtc"/>
|
||||
! <vfs>
|
||||
! <dir name="dev"> <log/> <null/> <rtc/> <wifi/>
|
||||
! <dir name="dev"> <log/> <null/> <rtc/>
|
||||
! <jitterentropy name="random"/>
|
||||
! <jitterentropy name="urandom"/>
|
||||
! </dir>
|
||||
@ -47,7 +47,7 @@ snippet illustrates the use of the driver on the PinePhone:
|
||||
! <config>
|
||||
! <libc stdout="/dev/null" stderr="/dev/null" rtc="/dev/rtc"/>
|
||||
! <vfs>
|
||||
! <dir name="dev"> <log/> <null/> <rtc/> <wifi/>
|
||||
! <dir name="dev"> <log/> <null/> <rtc/>
|
||||
! <jitterentropy name="random"/>
|
||||
! <jitterentropy name="urandom"/>
|
||||
! </dir>
|
||||
@ -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.
|
||||
|
@ -12,6 +12,8 @@
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/component.h>
|
||||
#include <base/shared_object.h>
|
||||
#include <libc/component.h>
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
#include <base/log.h>
|
||||
@ -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_thread> _wpa;
|
||||
Constructible<Wifi::Frontend> _frontend;
|
||||
|
||||
Blockade _wpa_startup_blockade { };
|
||||
|
||||
struct Request_handler : Wifi::Firmware_request_handler
|
||||
{
|
||||
Signal_handler<Request_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<Construct_fn>("_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);
|
||||
|
@ -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 <os/vfs.h>
|
||||
#include <vfs/single_file_system.h>
|
||||
|
||||
/* DDE Linux includes */
|
||||
#include <lx_kit/init.h>
|
||||
|
||||
|
||||
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;
|
||||
}
|
@ -69,32 +69,6 @@ struct Rfkill_helper
|
||||
}
|
||||
};
|
||||
|
||||
Constructible<Rfkill_helper> 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> 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> rfkill_helper { };
|
||||
|
||||
Constructible<Firmware_helper> 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;
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
<dir name="dev"> <log/> <null/> <rtc/>
|
||||
<jitterentropy name="random"/>
|
||||
<jitterentropy name="urandom"/>
|
||||
<wifi/>
|
||||
</dir>
|
||||
<dir name="firmware">
|
||||
<tar name="wifi_firmware.tar"/>
|
||||
|
@ -267,7 +267,7 @@ append config { </wifi_config>
|
||||
<libc stdout="/dev/null" stderr="/dev/log" rtc="/dev/rtc"/>
|
||||
<vfs>
|
||||
<dir name="dev">
|
||||
<log/> <null/> <wifi/>
|
||||
<log/> <null/>
|
||||
<jitterentropy name="random"/>
|
||||
<jitterentropy name="urandom"/>
|
||||
<inline name="rtc">2018-01-01 00:01</inline>
|
||||
|
Loading…
x
Reference in New Issue
Block a user