diff options
Diffstat (limited to 'Replicant_contributors_meeting_27_28_July_2019_Paris_France/modems/Replicant_and_modems_Samsung-ipc.tex')
-rw-r--r-- | Replicant_contributors_meeting_27_28_July_2019_Paris_France/modems/Replicant_and_modems_Samsung-ipc.tex | 805 |
1 files changed, 805 insertions, 0 deletions
diff --git a/Replicant_contributors_meeting_27_28_July_2019_Paris_France/modems/Replicant_and_modems_Samsung-ipc.tex b/Replicant_contributors_meeting_27_28_July_2019_Paris_France/modems/Replicant_and_modems_Samsung-ipc.tex new file mode 100644 index 0000000..704d123 --- /dev/null +++ b/Replicant_contributors_meeting_27_28_July_2019_Paris_France/modems/Replicant_and_modems_Samsung-ipc.tex @@ -0,0 +1,805 @@ +\documentclass{beamer} +\usepackage[english]{babel} +\usepackage{color} +\usepackage{graphicx} +\usepackage{ifthen} +\usepackage[utf8]{inputenc} +\usepackage{listings} +\usepackage{pdfpages} + +\lstdefinestyle{terminal}{ + backgroundcolor=\color{black}, + basicstyle=\scriptsize\color{green}, +} + +%% Based on: +%% https://tex.stackexchange.com/questions/136900/insert-a-full-page-image +\newcommand{\pictureframe}[1] { + { + \begin{frame} + \noindent + \resizebox{\textwidth}{\textheight} + {\includegraphics{#1}} + \hspace*{-\textwidth} + \end{frame} + } +} + +\usetheme{Singapore} + +\title{Samsung-ipc compatible modems in Replicant} +\author{Denis 'GNUtoo' Carikli} +\date{\today} + +\begin{document} + +\maketitle + +%% TODO: Using \itemize{} fails to compile +%% TODO: convert \center frames to chapter title + +\begin{frame} + \center{Samsung IPC} +\end{frame} + +\begin{frame} + \center{Samsung IPC: Hardware part} +\end{frame} + +\begin{frame} + \center{XMM626 $\leftarrow$RAM$\rightarrow$SOC } + \begin{itemize} + \item Galaxy S (I9100) + \item Nexus S (I902x) + \item Galaxy Tab (unsupported) + \end{itemize} +\end{frame} + +\begin{frame} + \center{XMM626 $\leftarrow$RAM$\rightarrow$SOC: Isolation } + \begin{itemize} + \item Nexus S: The modem kernel driver shows that part of a RAM chip is shared between the modem and the SOC + \item No hardware guarantees that the modem cannot take control of the SOC + \item IOMMU: + \begin{itemize} + \item Requires a mainline kernel to trust the code + \item And the SOC documentation on that... + \item And people having analyzed its security... + \item And to be setup before the RAM is even initialized... + \item But the bootloader is not free software... + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame} + \center{XMM626 $\leftarrow$MIPI$\rightarrow$SOC } + \begin{itemize} + \item Galaxy Nexus (I9250) + \item Galaxy Tab II 7.0 (P3100) + \item Galaxy Tab II 10.1 (P5100) + \end{itemize} +\end{frame} + +\begin{frame} + \center{XMM626 $\leftarrow$MIPI$\rightarrow$SOC: Isolation } + \begin{itemize} + \item Not analyzed in depth but probably ok + \item Same interface than camera and screens + \end{itemize} +\end{frame} + +\begin{frame} + \center{XMM626 $\leftarrow$HSIC$\rightarrow$SOC } + \begin{itemize} + \item Galaxy S2 (I9100) + \item Galaxy SIII (I9300) + \item Galaxy Note (N7000) + \item Galaxy Note II (N7100) + \item Galaxy Note 8.0 (N5100) + \end{itemize} +\end{frame} + +\begin{frame} + \center{XMM626 $\leftarrow$HSIC$\rightarrow$SOC: Isolation } + \begin{itemize} + \item No DMA to the SOC RAM + \item USB-like bus: USB without the PHY + \item The host need to reset the bus to get the devices re-enumerated + \item $\rightarrow$ More complicated for the modem to become a keyboard + \item Ideally (not looked into yet): + \begin{itemize} + \item usbguard + \item USB peripherals whitelist + \item $\rightarrow$ re-usable for USB modems (GTA04, PinePhone, Librem5, etc). + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame} + \center{Samsung IPC} + \begin{itemize} + \item We will look more specifically at the case with the XMM626 connected through HSIC. + \item Other transports are similar: transports are abstracted by the kernel driver and libsamsung-ipc transport drivers. + \end{itemize} +\end{frame} + +\pictureframe{output/xmm626_hsic.png} + +\begin{frame} + \center{The samsung-ipc protocol} + \begin{itemize} + \item Asyncronous + \item $\rightarrow$ You get asyncronous responses from the modem + \item $\rightarrow$ You match with the request (sequence numbers) + \item $\rightarrow$ libsamsung-ril needs receive asyncronous responses too + \item $\rightarrow$ More complex design with callbacks + \end{itemize} +\end{frame} + +\begin{frame} + \center{libsamsung-ril} +\end{frame} + +\begin{frame} + \center{The initialization not very different from the reference-ril} +\end{frame} +\lstset{language=C} +\begin{lstlisting} + RIL_RadioFunctions ril_radio_functions = { + RIL_VERSION, + ril_on_request, + ril_on_state_request, + ril_supports, + ril_on_cancel, + ril_get_version + }; + ... + + const RIL_RadioFunctions *RIL_Init( + const struct RIL_Env *env, int argc, + char **argv) { + ... + return radio_functions; + } +\end{lstlisting} + +\begin{frame} + \center{The interface with rild is not that different either} +\end{frame} +\lstset{language=C} +\begin{lstlisting} + void ril_on_request(int request, void *data, + size_t size, RIL_Token token) { + ... + ril_request_register(request, data, size, token); + ... +} +\end{lstlisting} + +\begin{frame} +\center{ril\_request\_register} +\end{frame} +\lstset{language=C} +\begin{lstlisting} + int ril_request_register(int request, void *data, + size_t size, RIL_Token token) { + ... + list_end = ril_data->requests; + ... + list = list_head_alloc(list_end, NULL, + (void *) ril_request); + ... + ril_data->requests = list; +} +\end{lstlisting} + +\begin{frame} + \center{Global ril\_Data variable} +\end{frame} + +\lstset{language=bash} +\begin{lstlisting}[style=terminal] +$ git grep "extern.*ril_data;" +samsung-ril.h:extern struct ril_data *ril_data; +\end{lstlisting} + +\begin{frame} + \center{Why?} + \begin{itemize} + \item Asyncronous design $\rightarrow$ Faster + \item Enqueue the request and continue serving new requests. + \item We will see how getting the response works in a second time + \end{itemize} +\end{frame} + +\begin{frame} + \begin{itemize} + \item We got a request to power on the phone from the RIL + \item We got rid of it by adding it to a list + \item Now what happens to it? + \end{itemize} +\end{frame} + +\begin{frame} + \center{RIL\_Init} +\end{frame} +\lstset{language=C} +\begin{lstlisting} + const RIL_RadioFunctions *RIL_Init( + const struct RIL_Env *env, int argc, + char **argv) { + ... + rc = pthread_create(&ril_data->request_thread, + &attr, ril_request_loop, NULL); + ... +} +\end{lstlisting} + +\begin{frame} + \center{ril\_request\_loop} +\end{frame} +\lstset{language=C} +\begin{lstlisting} + +void *ril_request_loop(void *data) { ... + while (1) { + do { + request = ril_request_find_status( + RIL_REQUEST_UNHANDLED); + ... + request->status = RIL_REQUEST_PENDING; + } while (request != NULL); + do { + ... + request = ril_request_find_status( + RIL_REQUEST_PENDING); + ... + rc = ril_request_dispatch(request); + } while (request != NULL); + } +\end{lstlisting} + +\begin{frame} + \center{ril\_request\_dispatch} +\end{frame} + +\lstset{language=C} +\begin{lstlisting} + int ril_request_dispatch( + struct ril_request *request) { + ... + for (i = 0; i < ril_request_handlers_count; + i++) { + ... + if (ril_request_handlers[i].request == + request->request) { + status = ril_request_handlers[i].handler( + quest->data, request->size, + request->token); + ... + request->status = status; ... + } ... + } ... + return 0; + } +\end{lstlisting} + +\begin{frame} + \center{ril\_request\_handler} +\end{frame} + +\lstset{language=C} +\begin{lstlisting} + struct ril_request_handler + ril_request_handlers[] = { + /* Power */ + { + .request = RIL_REQUEST_RADIO_POWER, + .handler = ril_request_radio_power, + }, ... + } +\end{lstlisting} + +\begin{frame} + \center{ril\_request\_radio\_power} +\end{frame} +\lstset{language=C} +\begin{lstlisting} + int ril_request_radio_power(void *data, + size_t size, RIL_Token token) { + ... + power_state = *((int *)data); + ... + if (power_state > 0) { + request_data.state = + IPC_PWR_PHONE_STATE_REQUEST_NORMAL; ... + } else { + request_data.state = + IPC_PWR_PHONE_STATE_REQUEST_LPM; ... + } ... + rc = ipc_fmt_send(ipc_fmt_request_seq(token), + IPC_PWR_PHONE_STATE, IPC_TYPE_EXEC, + (void *) &request_data, + sizeof(request_data)); ... + } +\end{lstlisting} + +\begin{frame} + \center{ipc\_fmt\_send} +\end{frame} +\lstset{language=C} +\begin{lstlisting} + int ipc_fmt_send(unsigned char mseq, + unsigned short command, unsigned char type, + const void *data, size_t size) { + ... + ipc_fmt_data = (struct ipc_fmt_data *) + client->data; + ... + rc = ipc_client_send(ipc_fmt_data->ipc_client, + mseq, command, type, data, size); + ... +} + +\end{lstlisting} + +\begin{frame} + \center{The rest happens in libsamsung-ipc} +\end{frame} + +\lstset{language=bash} +\begin{lstlisting}[style=terminal] +$ git grep IPC_PWR_PHONE_STATE_REQUEST_NORMAL + include/pwr.h: + #define IPC_PWR_PHONE_STATE_REQUEST_NORMAL 0x0202 +$ git grep ipc_client_send + include/samsung-ipc.h: + int ipc_client_send(struct ipc_client *client, ... + samsung-ipc/ipc.c: + int ipc_client_send(struct ipc_client *client, ... +\end{lstlisting} + + +\begin{frame} + \center{Now what happens with notifications from the modem?} +\end{frame} + +\begin{frame} + \center{Again RIL\_Init} +\end{frame} + +\lstset{language=C} +\begin{lstlisting} + const RIL_RadioFunctions *RIL_Init( + const struct RIL_Env *env, + __attribute__((unused)) int argc, + __attribute__((unused)) char **argv) { + ... + rc = ril_client_loop(ril_clients[i]); + ... + } +\end{lstlisting} + +\begin{frame} + \center{ril\_clients[i]?} +\end{frame} + +\begin{frame} + \center{ril\_clients} +\end{frame} +\lstset{language=C} +\begin{lstlisting} +struct ril_client *ril_clients[] = { + &ipc_fmt_client, + &ipc_rfs_client, + &srs_client, +}; +\end{lstlisting} + +\begin{frame} + \center{IPC and RFS} + \begin{itemize} + \item RFS: Modem's remote filesystem (EFS) + \item SRS: For the audio part + \item IPC: The rest of the protocol + \end{itemize} +\end{frame} + +\lstset{language=bash} +\begin{lstlisting}[style=terminal] +$ git grep XMM626_SEC_MODEM_IPC0_DEVICE + modems/xmm626/xmm626_sec_modem.c: + fd = open(XMM626_SEC_MODEM_IPC0_DEVICE, + O_RDWR | O_NOCTTY | O_NONBLOCK); + modems/xmm626/xmm626_sec_modem.h: + #define XMM626_SEC_MODEM_IPC0_DEVICE + "/dev/umts_ipc0" + $ git grep XMM626_SEC_MODEM_RFS0_DEVICE + modems/xmm626/xmm626_sec_modem.c: + fd = open(XMM626_SEC_MODEM_RFS0_DEVICE, + O_RDWR | O_NOCTTY | O_NONBLOCK); + modems/xmm626/xmm626_sec_modem.h: + #define XMM626_SEC_MODEM_RFS0_DEVICE + "/dev/umts_rfs0" +\end{lstlisting} + +\begin{frame} + \center{ril\_client\_loop} +\end{frame} +\lstset{language=C} +\begin{lstlisting} + int ril_client_loop(struct ril_client *client) { + ... + rc = pthread_create(&client->thread, &attr, + ril_client_thread, (void *) client); + ... + } + +\end{lstlisting} + +\begin{frame} + \center{ril\_client\_thread} +\end{frame} +\lstset{language=C} +\begin{lstlisting} + void *ril_client_thread(void *data) { + ... + client = (struct ril_client *) data; + ... + rc = client->handlers->loop(client); + ... + } +\end{lstlisting} + +\begin{frame} + \center{ril\_client} +\end{frame} +\lstset{language=C} +\begin{lstlisting} +struct ril_client ipc_fmt_client = { + .id = RIL_CLIENT_IPC_FMT, + .name = "IPC FMT", + .handlers = &ipc_fmt_handlers, + .callbacks = &ipc_fmt_callbacks, +}; +\end{lstlisting} + +\begin{frame} + \center{ipc\_fmt\_handers} +\end{frame} +\lstset{language=C} +\begin{lstlisting} +struct ril_client_handlers ipc_fmt_handlers = { + .create = ipc_fmt_create, + .destroy = ipc_fmt_destroy, + .open = ipc_fmt_open, + .close = ipc_fmt_close, + .loop = ipc_fmt_loop, +}; +\end{lstlisting} + +\begin{frame} + \center{ipc\_fmt\_loop} +\end{frame} + +\lstset{language=C} +\begin{lstlisting} + int ipc_fmt_loop(struct ril_client *client) { + ... + rc = ipc_client_recv(data->ipc_client, + &message); + ... + rc = ipc_fmt_dispatch(client, &message); + ... + } +\end{lstlisting} + +\begin{frame} + \center{ipc\_fmt\_dispatch} +\end{frame} +\lstset{language=C} +\begin{lstlisting} + int ipc_fmt_dispatch(struct ril_client *client, + struct ipc_message *message) { + ... + for (i = 0; + i < ipc_fmt_dispatch_handlers_count; i++) { + ... + if (ipc_fmt_dispatch_handlers[i].command == + message->command) { + ... + rc = ipc_fmt_dispatch_handlers[i].handler( + message); + ... + } + } + ... +} +\end{lstlisting} + +\begin{frame} + \center{ipc\_fmt\_dispatch\_handlers} +\end{frame} +\lstset{language=C} +\begin{lstlisting} + struct ipc_dispatch_handler + ipc_fmt_dispatch_handlers[] = { + /* Power */ + { + .command = IPC_PWR_PHONE_PWR_UP, + .handler = ipc_pwr_phone_pwr_up, + }, +\end{lstlisting} + +\begin{frame} + \center{ipc\_pwr\_phone\_pwr\_up} +\end{frame} +\lstset{language=C} +\begin{lstlisting} + int ipc_pwr_phone_pwr_up(__attribute__((unused)) + struct ipc_message *message) { + ril_radio_state_update(RADIO_STATE_OFF); + + return 0; + } +\end{lstlisting} + +\begin{frame} + \center{libsamsung-ipc} +\end{frame} + +\begin{frame} + \center{ipc\_client\_send} +\end{frame} +\lstset{language=C} +\begin{lstlisting} + int ipc_client_send(struct ipc_client *client, + unsigned char mseq, unsigned short command, + unsigned char type, const void *data, + size_t size) { + ... + memset(&message, 0, sizeof(message)); + message.mseq = mseq; + message.aseq = 0xff; + message.command = command; + message.type = type; + message.data = (void *) data; + message.size = size; + + return client->ops->send(client, &message); +} +\end{lstlisting} + +\begin{frame} + \center{client$\rightarrow$ops$\rightarrow$send} +\end{frame} + + +\begin{frame} + \center{ipc\_client\_create} +\end{frame} +\lstset{language=C} +\begin{lstlisting} +struct ipc_client *ipc_client_create(int type) { + ... + rc = ipc_device_detect(); + ... + switch (type) { + ... + case IPC_CLIENT_TYPE_FMT: + client->ops = + ipc_devices[device_index].fmt_ops; + break; + ... + } + ... +} +\end{lstlisting} + +\begin{frame} + \center{ipc\_device\_detect} +\end{frame} +\lstset{language=C} +\begin{lstlisting} + int ipc_device_detect(void) { + ... + fd = open("/proc/cpuinfo", O_RDONLY); + ... + if (strncmp(line, "Hardware", 8) == 8) { + ... + if (... && strcmp(kernel_version, + ipc_devices[i].kernel_version) != 0) + ... +} + +\end{lstlisting} + +\begin{frame} + \center{ipc\_devices} +\end{frame} +\lstset{language=C} +\begin{lstlisting} +struct ipc_device_desc ipc_devices[] = { + ... + { + .name = "i9300", + .board_name = "smdk4x12", + .kernel_version = NULL, + .fmt_ops = &i9300_fmt_ops, + .rfs_ops = &i9300_rfs_ops, + .handlers = &i9300_handlers, + .gprs_specs = &i9300_gprs_specs, + .nv_data_specs = &i9300_nv_data_specs, + }, +\end{lstlisting} + +\begin{frame} + \center{ipc\_client\_ops} +\end{frame} +\lstset{language=C} +\begin{lstlisting} +struct ipc_client_ops i9300_fmt_ops = { + .boot = i9300_boot, + .send = xmm626_sec_modem_fmt_send, + .recv = xmm626_sec_modem_fmt_recv, +}; +\end{lstlisting} + +\begin{frame} + \center{xmm626\_sec\_modem\_fmt\_send} +\end{frame} +\lstset{language=C} +\begin{lstlisting} + int xmm626_sec_modem_fmt_send( + struct ipc_client *client, + struct ipc_message *message) { + ... + rc = client->handlers->write( + client->handlers->transport_data, + p, length - count); + } +\end{lstlisting} + + +\begin{frame} + \center{i9300\_handlers} +\end{frame} +\lstset{language=C} +\begin{lstlisting} + struct ipc_client_handlers i9300_handlers = { + .read = i9300_read, + .write = i9300_write, + .open = i9300_open, + .close = i9300_close, + .poll = i9300_poll, + .transport_data = NULL, + .power_on = i9300_power_on, + .power_off = i9300_power_off, + .power_data = NULL, + .gprs_activate = i9300_gprs_activate, + .gprs_deactivate = i9300_gprs_deactivate, + .gprs_data = NULL, + .data_create = i9300_data_create, + .data_destroy = i9300_data_destroy, + }; +\end{lstlisting} + +\begin{frame} + \center{i9300\_open} +\end{frame} +\lstset{language=C} +\begin{lstlisting} +int i9300_open(void *data, int type) +{ + ... + transport_data->fd = + xmm626_sec_modem_open(type); + ... + return 0; +} +\end{lstlisting} + +\begin{frame} + \center{xmm626\_sec\_modem\_open} +\end{frame} +\lstset{language=C} +\begin{lstlisting} +int xmm626_sec_modem_open(int type) { + switch (type) { + case IPC_CLIENT_TYPE_FMT: + fd = open(XMM626_SEC_MODEM_IPC0_DEVICE, + O_RDWR | O_NOCTTY | O_NONBLOCK); + break; + case IPC_CLIENT_TYPE_RFS: + fd = open(XMM626_SEC_MODEM_RFS0_DEVICE, + O_RDWR | O_NOCTTY | O_NONBLOCK); + break; + default: + return -1; + } + ... +} +\end{lstlisting} + +\begin{frame} + \center{xmm626\_sec\_modem\_fmt\_send} +\end{frame} +\lstset{language=bash} +\begin{lstlisting}[style=terminal] + $ git grep XMM626_SEC_MODEM_IPC0_DEVICE + devices/xmm626/xmm626_sec_modem.h: + #define XMM626_SEC_MODEM_IPC0_DEVICE "/dev/umts_ipc0" + $ git grep XMM626_SEC_MODEM_RFS0_DEVICE + devices/xmm626/xmm626_sec_modem.h: + #define XMM626_SEC_MODEM_RFS0_DEVICE "/dev/umts_rfs0" +\end{lstlisting} + +\begin{frame} + \center{i9300\_write} +\end{frame} +\lstset{language=C} +\begin{lstlisting} + int i9300_write(void *data, + const void *buffer, size_t length) { + ... + rc = xmm626_sec_modem_write( + transport_data->fd, buffer, length); + + return rc; +} +\end{lstlisting} + +\begin{frame} + \center{xmm626\_modem\_write} +\end{frame} +\lstset{language=C} +\begin{lstlisting} + int xmm626_sec_modem_write(int fd, + const void *buffer, size_t length) { + ... + status = ioctl(fd, IOCTL_MODEM_STATUS, 0); + if (status != STATE_ONLINE && + status != STATE_BOOTING) + return -1; + + rc = write(fd, buffer, length); + + return rc; +} +\end{lstlisting} + +\begin{frame} + \center{Sharing the work with other Android distributions} + \begin{itemize} + \item Not complete enough to be merged in LineageOS + \end{itemize} +\end{frame} + +\begin{frame} + \center{Sharing the work with GNU/Linux distributions} + \begin{itemize} + \item Freesmartphone.org + \item Ofono + rild + libamsung-ril + libsamsung-ipc + \item Ofono + libsamsung-ipc + \item PostmarketOS? + \item PureOS, Parabola? + \end{itemize} +\end{frame} + +\begin{frame} + \center{Discussions:} + \begin{itemize} + \item Sharing code with other distributions? + \item USB Guard? + \item Device requirements: Require modem to be isolated ? + \item Other modems and GNU/Linux stack (PinePhone, GTA04)? + \item Using GNU/Linux modem stack as much as possible? + \item Automatic testing infrastructure and ofono? + \item GNU/Linux and testing? + \end{itemize} +\end{frame} + +\begin{thebibliography}{99} +\end{thebibliography} + +\end{document} |