This issue is to split out the progress on getting qualcomm modems working from the general cellular modem issue since I like to document the progress also for myself, and for everyone else that wants to look into this. Last but not least to avoid duplicate work.
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Child items 0
Show closed items
No child items are currently assigned. Use child items to break down this issue into smaller parts.
Linked items 0
Link issues together to show that they're related.
Learn more.
All of this work is currently on my dev phone and not packaged since all of this is explorative at this point.
My understanding currently is that we could maybe completely skip rild on qualcom modems since ofono can talk qmi and there is a project here that translates qmi to qmuxd socket messages. Not sure though.
Quick rundown of what I have done so far for documentation purposes and in case someone else also wants to look into this and as a memo for myself.
I run qmuxd by simply ripping /vendor/lib64 /system/lib64 and /system/bin/linker64 out of the lineageOS system and throw them on my phone, this allows qmuxd to run using the lineageOS bionic stuff. (For development purposes only, to be trimmed down/chrooted/namespaced/seccomp'd to smithereens)
The error creating the sockets above was from me not really paying attention. qmuxd calls setuid(1001) so even though i was running it as root and prepared the /dev/socket/... folders for it, it failed of course.
I now run socat PTY,link=/tmp/qmiserial2qmuxd .pty,cfmakeraw EXEC:"./qmiserial2qmuxd" which requires a small patch to add an #ifdef ANDROID guard for the termio.h include.
This successfully connects to qmuxd which we can also confirm by running qmuxd in strace
open_qmuxd_socket: connected to qmuxd and received client id 1
Cool, now we want something to run test-queries against it, so we compile libqmi which contains a command line utility qmiclient. This requires a small patch to build against musl that isn't in the latest stable tarball yet.
send_qmuxd_request: [1]< 0 34qmuxd_read_loop: unknown/unsupported qmuxd message 11handle_qmuxd_response: [1, syserr=-5, qmierr=0, length=3360]< 11 0handle_qmuxd_response: qmuxd reports syserr; not forwarding to serial
Well, actually we get a bit less output, but i removed the call to exit() on error.
And this is where I'm at now currently. Next planned step. Patch qmiserial2qmuxd a bit more to get the raw response from qmuxd and/or get some logging output from qmuxd, but from straceing it, it doesn't seem like it tries to log anything to android's debuggerd socket, will need to take a closer look though.
To get debug output from qmuxd and rmt_storage, we can run the following python script. This creates the socket these log to and sends their messages to stdout there is some binary garbage (packet headers?) in there, but we can read the text messages just fine:
rmt_storageRemote storage service is not supported on undefined target
Cleaned up output from qmuxd:
libmdmdetectESOC framework not supportedlibmdmdetectFound internal modem: modemDiag_Lib Diag_LSM_Init: Failed to open handle to diag driver, error = 13libmdmdetectESOC framework not supportedlibmdmdetectFound internal modem: modemQC-QMIlinux_qmi_qmux_io_pwr_up_init.c: Unable to open wakelock file = /sys/power/wake_lock, error [13:Permission denied]QC-DS-LIBqmuxd: linux_qmi_read_sysfs_config: couldn't open file /sys/module/f_rmnet/parameters/rmnet_ctl_chQC-DS-LIBqmuxd: linux_qmi_read_sysfs_config: couldn't open /sys/module/rmnet/parameters/rmnet_ctl_chQC-QMIqmuxd: Cannot parse qmi_config.undefined.control_ports_len, config file /system/etc/data/qmi_config.xmlQC-DS-LIBqmuxd: Failed to load XML configuration [/system/etc/data/qmi_config.xml] for target [undefined], all ports disabledQC-QMIlinux_qmi_qmux_io_stop_watchdog_timer(): invalid timer_id for conn_id=60
This is pseudocode for my understanding of what the check does that spits out the undefined target message in rmt_storage:
var baseband = property_get("ro.baseband");var supported_basebands = ["msm", "apq", "dsda3", "sqlte"];if(!supported_basebands.contains(baseband)){ android_log_print("rmt_storage", "Remote storage service is not supported on %s target\n", baseband); property_set("ctl.stop", "rmt_storage"); exit(1);}
property_get is an import and my understanding of how this works is that it queries /dev/socket/property_service which I think is provided by android's init.
So the options are
a) binary patch it
b) write a simple emulator for the property service that feeds it whatever we need, it's it's quite likely qmuxd calls property_get() too and it might be used in other places in the binary.
Actually, it's reading the properties from /dev/__properties__ and writes to /dev/socket/property_service. @opendata26 graciously provided his /dev/__properties__ folder and his /property_contexts file. Slapping these into my file system sucessfully get's past that crash and we get a bit further in running rmt_service. We can trim these down later too, probably.
K(�y rmt_storageShared memory initialised successfully. K(��� rmt_storageFailed to open partition /dev/block/bootdevice/by-name/modemst1 err 2 (No such file or directory). This is very bad!!! K(B� rmt_storageUnable to open /dev/block/bootdevice/by-name K(�> rmt_storageFailed to open partition /dev/block/bootdevice/by-name/modemst2 err 2 (No such file or directory). This is very bad!!! K(6�" rmt_storageUnable to open /dev/block/bootdevice/by-name K(��Q rmt_storageFailed to open partition /dev/block/bootdevice/by-name/fsc err 2 (No such file or directory). This is very bad!!! K(��v rmt_storageUnable to open /dev/block/bootdevice/by-name K(��� rmt_storageFailed to open partition /dev/block/bootdevice/by-name/fsg err 2 (No such file or directory). This is very bad!!! K(��� rmt_storageUnable to open /dev/block/bootdevice/by-name K(-�� rmt_storage0 GPT partitions found
is used for data interconnect both among and within computers.
This leads me to believe it's actually trying to talk to the radio :)
Reasons why it fails here could be manyfold, either e.g. missing permissions on the user(group) it drops to, or the fact that the android properties i currently use aren't from this phone and it could try to access the wrong address(?).
To test working around permission issues I decided it's time to start LD_PRELOAD hacking
int setuid(int uid){ return 0;}
compile with gcc -shared -fPIC -nostdlib lel.c -o lel.so. This nukes their calls to drop privileges and keeps them running as root, this is just for testing and not meant for production.
When we now run LD_PRELOAD=$PWD/lel.so strace ./rmt_storage we get.
recvfrom(13, 0x7fe8bd5e70, 20, MSG_DONTWAIT, NULL, NULL) = -1 ENOMSG (No message of desired type)pselect6(14, [12 13], NULL, NULL, NULL, NULL
Which, could be okay? Maybe there is just no message, not sure, at least it's not exiting or crashing anymore.
When we now run qmuxd with the same hack, we get
QC-QMIlinux_qmi_qmux_io.c: Unable to open port id /dev/smdcntl0, error [110:Connection timed out]K�x} QC-QMIqmi_qmux_open_connection: QMI_QMUX_IO_PLATFORM_OPEN_CONN failed conn_id=0 rc=-1 K�&u� QC-DS-LIBqmuxd: opening connection for conn_id=0 [DATA5_CNTL] failed on attempt 2, Waiting 50 milliseconds before retryK+��<�QC-QMIlinux_qmi_qmux_io.c: Unable to open port id /dev/smdcntl0, error [110:Connection timed out]K+��ƔQC-QMIqmi_qmux_open_connection: QMI_QMUX_IO_PLATFORM_OPEN_CONN failed conn_id=0 rc=-1
In dmesg we get a bunch of
[ 2342.217539] smd_pkt_open: wait on smd_pkt_dev id:0 allocation failed rc:-110
I guess there is a higher chance of qualcomm having hacked something into the kernel that misuses infiniband addressing than that it actually using inifiniband to communicate with the modem (which is normally used in supercomputers and large SAN's for datacenters)
I stumbled on this thread, and I'm glad to see you've made some sense out of my work and have gotten started making broader applications of it!
AF_IB is likely actually AF_MSMIPC, the Qualcommm IPC socket type, but it's not mainlined, so tools like strace interpret the value as a different constant name. I'm not very familiar with postmarketOS yet -- are you running a mainline kernel (not Android)? If you're not using an Android kernel, qmuxd and rmt_storage probably aren't going to work. There is an open-source equivalent of rmt_storagehere, and I have a fork that works on top of AF_MSMIPC.
I would probably recommend skipping qmuxd. For a long time, I didn't understand what magic it was doing to send QMI since I couldn't get my tools to work. I finally figured out the issue was that poll() on the smdcntl0 device didn't work how qmicli et al expected. I fixed that with this LD_PRELOAD wrapper. This might be specific to Qualcomm's patches in the Android kernels, though. Anyway, if you can find a serial device you can talk QMI to, I would use that directly rather than qmuxd and qmiserial2qmuxd.
My readme here might have some pointers on getting the modem up (maybe your SMD timeout issues), but maybe your kernel/device is different. It also might not be necessary if you're using enough proprietary stuff -- from what I can tell the proprietary things are more robust at initialization right now, so apparently I haven't learned and implemented some parts of that process.
I won't have a lot of time to hack on this, but I'll try to keep track and help where I can. When you get oFono up, I can show you some patches that haven't merged yet, to add some features like voicecall support.
Hey there! It's awesome you're chiming in, i haven't had a lot of time to hack on this either lately. But if you do have time, I do have some questions.
AF_IB is likely actually AF_MSMIPC, the Qualcommm IPC socket type, but it's not mainlined, so tools like strace interpret the value as a different constant name.
Ahh! That'd make sense. I'll look into that.
are you running a mainline kernel (not Android)?
No this is currently an android kernel running alpine linux userland (musl/busybox). Specifically it's running the LineageOS kernel for my phone. (Our plan is to eventually move to mainline, but that's probably not practical to start with, so we still mostly use outdated android kernels, except for a few phones where mainlining work has already been started, e.g. the N900).
I would probably recommend skipping qmuxd.
Sorry, you're way more knowledgeable than me. My understanding was that we need qmuxd to talk to the modem? My understanding was that you can't talk to newer chipsets via QMI anymore and need qmuxd to talk to the modem via shared memory devices. Is that wrong?
Anyway, if you can find a serial device you can talk QMI to, I would use that directly rather than qmuxd and qmiserial2qmuxd.
Uhh, it shows I have no clue what I'm doing here, do you have any pointers on how I would figure out if my device can talk QMI directly (and possibly how to identify the appropriate serial device)?
Anyways, I hope I can look a bit more deeply into your response in the comming days. I really appreciate you finding this. I didn't dare trying to ping you yet with anything before looking further into this!
Sorry, you're way more knowledgeable than me. My understanding was that we need qmuxd to talk to the modem?
My knowledge might also be outdated at this point, as my phone was released in 2013. Maybe you are right about the newer chipsets. Also, maybe you should start with the proprietary stack after all, until you see some success. Anyway, on my device (Samsung GS4 Mini LTE aka I9195 aka serranoltexx), qmuxd talks QMI to SMD serial devices, exposing a socket-based protocol for rild, which qmuxd proxies to the serial device (I think one reason is preventing multiple clients from interfering with each other talking to the same serial device.) When I use the wrapper I linked above, I can directly use the serial device similarly to a QMI USB modem attached to a PC, or how the phone looks to a PC when I put it in a tethering mode (something like setprop sys.usb.config diag,serial_smd,serial_tty,rmnet_bam,mass_storage,adb)
What device do you have? To see if your phone is similar to mine, try looking in /sys/class/smdpkt to see if you have smdpkt devices. For me, /dev/smdcntl0 is the main one for phone functions. I think things like GPS are available on others. There is also information in /sys/kernel/debug/smd , although I'm drawing a blank now on how I've correlated the names in tbl with devices.
Based on your rmt_storage errors and qmuxd timing out trying to connect to the SMD device, I would guess the modem is not booting. On my device, if rmt_storage isn't working, then the modem fails and can't be talked to over SMD. When you blocked the setuid() call, what is rmt_storage's log output?
I got QMI calls working on my i9195!! Due to time shortage I didn't do something really cool like send an SMS, but I'm pretty confident that's just a matter of getting the right packages built (see bottom of post.) Maybe somebody else will have the honor of sending the first SMS from postmarketOS on a Qualcomm device. ;)
Here are some commands and example output that will hopefully help others.
Next steps are to install/build uqmi (it can send SMSs; as far as I know qmicli doesn't) or ofono (I see it's in the Alpine testing repo, might need some patching to point to smdcntl0, and will need libsmdpkt_wrapper.so as above. See my Android fork for some help on that; of course not all of the changes will be needed.) There is also plenty more work to do with automating/packaging the above stuff, cleaning up the patches I made to get it working, making sure it's robust [could be some timing-related flakiness], etc.
(If anyone's kernel has the mainline AF_QIPCRTR, we will need to un-do some patches I made to get this stuff working with AF_MSM_IPC which ships with Android kernels. That's for rmtfs, at least. Maybe the serial QMI device is a little different on mainline too.)
Next steps are to install/build uqmi (it can send SMSs; as far as I know qmicli doesn't) or ofono (I see it's in the Alpine testing repo, might need some patching to point to smdcntl0, and will need libsmdpkt_wrapper.so as above.
I'd recommend ofono, that is what UIs like Plasma Mobile, LuneOS UI etc. are compatible with.
Just to make sure we're on the same page with the firmware, it comes from a partition that ships on the device. I lean toward not packaging it -- they are probably copyrighted and not redistributable, and also the images might have country/network-specific customizations we don't necessarily want to deal with knowing about. The updating is interesting, but we'd probably have to look on XDA and download sketchy files, without a lot of insight into whether they are actually universally better, or safe. I know security updates are a focus of this project, so maybe there is some middle ground of tracking available firmware versions and just notifying the user if a newer one is available?
This firmware image mount is kind of a pain with the way main/postmarketos-base/firmwareload.sh is now, because not only does it need a mount point, but there is a subdirectory within the partition. Thoughts on how to do this best? I am thinking about changing that script to just recursively search /lib/firmware, so the existing structure can be retained, and I can mount at something like /lib/firmware/modem and it will work too. But I don't know much about the intended structure of that directory, beyond what I guess by grepping for /lib/firmware/ in aports.
I will try ofono when I have some time, maybe later this week.
Regarding firmware files, after discussing last year we agreed upon packaging the firmware files, and not using Android's firmware partition. See the FAQ for reasoning. If you think this is a mistake and have good arguments for doing it differently, then feel free to open the discussion again. One idea to work around the redistribution problem is proposed in #797 (closed). Right now the firmware packages are simply not part of the binary package repository, so they get built when users run pmbootstrap install.
When packaged this way, the firmware load script should also work, right? If not, we can of course extend it.
Ah, I see now you've gone through some of the same firmware concerns already. OK, I will see how it goes with packaged firmware. I noticed the modem firmware file I got had a couple of other partitions it, so that could be something to watch out for -- if the modem/bootloader/etc. is reading those partitions and we're feeding it mismatched firmware files from our package, something might get confused. (Though I've had to go to a lot of trouble to port rmtfs, supposedly because the modem can't see the eMMC storage, so maybe it's not an issue.)
Tonight I sent some SMS's with ofono! I am out of time to package ofono nicely, but I've polished some of the code from before. Firmware is packaged, and you don't need to make those symlinks in /boot yourself. It's at https://github.com/scintill/pmbootstrap/tree/qmimodem2 . Check out this commit to see what you need to add in your device, if you have a similar one. The commands to work with this code are similar to before, but I moved the LD_PRELOAD libs to /usr/lib/preload.
Here's a quick dump of patches to Alpine's ofono package (some is hacky debugging):