Hi there!

Welcome to Javier Lopez-Gomez’s personal site :wave:! I’m a HPC software engineer, Ph.D. in Computer Science and Technology, and exCERNie (@root-project), passionate about C++, OS internals, and compiler design / implementation.
You can read a bit more about me here. A summarized version of the CV (résumé) can be downloaded here.

Ideally, this site will also host posts about a number of interesting topics.

Summer WG21 Meeting; trip report

This blog has been somewhat quiet during the last few months, mostly due to lack of time (but life has been quite hectic in other aspects!). Aaaand… a good reason to break this silence is to report about the summer WG21 meeting!

A few days ago, 16th to 21st June, the Summer WG21 (ISO C++ committee) meeting took place in Sofia, Bulgaria. It was, actually, my first face-to-face meeting since I joined the committee in February. The gathering took place in the Millenium Sofia Grand Hotel conference rooms. A room was reserved for each of EWG (Core Language Evolution), LEWG (Library Evolution), CWG (Core Language Wording), and LWG (Library Wording). An additional conference room was shared by all Study Groups, which made use of it according to the agenda. This meeting was decisive for the final inclusion of proposals into the C++26 draft (mind NBs comments).

On Sunday 15th, pm, there was a welcome session for newcomers, courtesy of Jens Maurer and Nina Ranns. The meeting officially started on Monday 16th, 9am, with a plenary session, after which each of the parallel tracks started. On Saturday 21st, am, another plenary session took place, where the groups summarized and reported their progress, followed by polls for each of the motions that came out of CWG and LWG. If you are not familiar with the organization and operation of the committee, I strongly recommend this and this reading.
OT: one of the very big surprises of the week was that I met some friends from CERN after quite some time (yes, I am looking at you, Jonas R., Jolly C., and Axel N.!). And I also met new people and had some very interesting conversations, which is unvaluable!

Returning back to C++, for the curious reader, find below a list of (IMO) interesting papers presented and voted in some of the sessions:

From the plenary session on Saturday 21st [1], the most remarkable outcome is that Reflection for C++26 was finally approved. IIRC, a total of 6 motions related to reflection were voted (5 from CWG; 1 from LWG)! Also, remarkably, EWG saw an astonishing 54 papers throughout the whole week!

Finally, I would like to thank you all for this awesome week – and see you in the upcoming Kona, HI (USA) meeting, 3rd November - 8th November, but this time (remotely) though teleconference!


[1] A more detailed trip report by Herb Sutter is available here.

p18clock update 2025

Long after the p18clock hobby project stalled (2012), a number of updates came in for 2025 – some based on the latest changes in libledmtx merged last year, e.g. the support for user-defined viewports. This makes it possible to have a larger framebuffer than the actual physical display and to define which part of it is visible.

This feature is now leveraged by the AUTO mode in p18clock to simulate vertical scrolling text (where the framebuffer is large enough to hold up to four lines of text, and the viewport is updated to show only a part of it). This obviously requires a libledmtx build that has ENABLE_VIEWPORT=1.

Here is the list of firmware changes:

Additionally, a couple of changes went in for the prototype board:

  • Added missing 10 nF decoupling capacitors
  • Installed a proper (micro-USB-B) power connector
  • Desoldered LM35 temperature sensor from the board and attached it via a small pigtail cable. Special care has to be taken as the analog LM35 output is highly vulnerable to EMI.

Last but not least, Kicad is being used to produce the circuit schematic and PCB design. The resulting Gerber file will be sent to jlcpcb for fabrication; components to be manually soldered when the PCBs are delivered. I’ll post updates here as soon as this progresses!

libledmtx-1.1.0 is out

As mentioned a few weeks ago, a number of new features were planned for libledmtx. This short follow-up post is an announcement of those features being officially available as of today. The new version has been tagged libledmtx-1.1.0. In particular, it brings:

  • Support for double buffer (see documentation for ledmtx_setbackbuffer() and ledmtx_swapbuffers()).
  • Allow for user-defined viewport (see ledmtx_setviewport()). This makes it possible to allocate a larger framebuffer than the physical display and change the visible surface as many times as needed.
  • Small optimizations regarding CPU time and access bank memory usage.
  • A test suite based on lit and gpsim.

Find more details here.

Resuming development of libledmtx

It has been a bit hectic in the last few months (and consequently a bit quiet here too). Here is some news: after a long period without any functional changes, I’d like to announce that the addition of some new features in libledmtx is scheduled for the next few weeks. Such features are mostly required for p18-LEDcube, but also useful for a future p18clock firmware update.

Specifically, the planned features are:

  • Support for double buffer. In this configuration, the driver reads from the frontbuffer, whereas the framebuffer manipulation routines act on the backbuffer. Once the backbuffer is ready, buffers can be swapped by using ledmtx_swapbuffers(). This in turn would enable viewports over the frontbuffer, i.e. having a frontbuffer larger than the actual display and only make a specific region visible.

  • Minor optimizations, mainly affecting the r393c164 driver. Small memory savings in the access bank are also expected.

  • Introduction of tests based on lit and the gpsim Microchip PIC simulator, enabling the validation of the library without relying on real hardware.

That’s all for now! Stay tuned!

Interesting reads on development in kernel-mode

This short post is about giving kudos to those books on the intricacies of kernel-mode that had an enormous impact on me and that were especially relevant for the implementation of my B.Sc. thesis around a decade ago. Without further ado, here is the list:

  • Understanding the Linux kernel: describes foundational concepts of the Intel x86 architecture and a in-depth view of the design of the Linux kernel. While the 3rd edition applied for Linux 2.6, it is still a valuable source of information.
  • Linux Device Drivers: this book can be seen as the practical counterpart of the previous book.
  • Designing BSD Rootkits: An Introduction to Kernel Hacking: one of the books that impressed me the most. Short and to the point explanation of rootkit mechanics, e.g. direct kernel object manipulation (DKOM) and kernel object hooking.

Happy reading!

Contemporary, a contributed theme for moderncv

Since 2012, I have been using the moderncv LaTeX package to prepare my CV. The moderncv class noticeably reduces the time required to typeset a nice-looking CV, yet it lacks an eye-catching modern theme.

In the last few days, I have been reworking my résumé and I took the chance to write a new theme that looks more up-to-date (see image). contemporary is largely based on the classic theme and makes use of PGF/TikZ for some of the decorations. A pull request for moderncv is up here. Enjoy!

Talk: git, from noob to expert

Back in 2019, during my doctoral studies, I was asked a number of git-related questions here and there by some members of the research group. Thus, I decided to prepare a slide deck for a talk/workshop to boost casual users’ knowledge. The talk covers git foundational concepts (e.g., blob / tree / commit objects, refs, index), as well as a quick overview of usual porcelain commands and scratching the surface of the plumbing layer.

Due to the general interest, the talk was given not only for the members of the ARCOS-UC3M research group, but also for other audiences. The slides are up here, just in case it can help other people :slightly_smiling_face:!

Fuzzing Against the Machine

Some months ago, my friends Antonio Nappa (@jeppojeps) and Eduardo Blázquez (@Fare9) finally released the book “Fuzzing Against the Machine”, for which I had the pleasure to write a foreword. The book covers fuzzing of embedded systems’ firmware leveraging tools such as QEMU and AFL / AFL++, with practical examples of vulnerability discovery on iOS, Android, and Samsung’s Mobile Baseband software, Shannon.

If you are interested in the topic, do not hesitate to take a look. The book is available on Amazon and Direct Digital (Packt).

Restoring the PCI configuration space of a device

Sometimes it’s useful to be able to restore the registers comprising the configuration space of a given PCI device to a known state, e.g. by the boot loader (so that the booted kernel finds the device in a specific state). To address this need, I wrote a simple script that generates a bunch of setpci commands compatible with setpci(8) (from the pciutils package) and GRUB2’s setpci command.

#!/bin/bash
#
# Generate a set of `setpci` commands that restore the contents of the PCI configuration space for the given device.
# The first argument is the address of the device whose configuration is to be dumped in one of the forms taken by
# the `lspci -s`, i.e. `[[[[<domain>]:]<bus>]:][<device>][.[<func>]]`; see lspci(8) for more information.
# The generated output can either be used by pciutils' setpci(8) or by GRUB2, which also has a `setpci` command.
lspci -xxx -s $1 | awk '
/^([0-9a-f]+):[0-9a-f]+:[0-9a-f]+.[0-9a-f]+ / { device = $1; }
/^[0-9a-f]{2}: / {
reg = strtonum("0x" $1);
printf("setpci -s %s", device);
for (i = 2; i <= NF; i++)
printf(" %02x=%s", reg++, $i);
printf("\n");
}
'

It takes a single argument in any of the forms taken by lspci -s, i.e. [[[[<domain>]:]<bus>]:][<device>][.[<func>]] that specifies the address of a device (or group of devices) whose configuration space is to be dumped, e.g.

# 0000:00:1f.3 is a 'Multimedia audio controller: Intel Corporation Tiger Lake-LP
#                    Smart Sound Technology Audio Controller (rev 20)' on my machine
$ sudo ./gen_restore_pciconf.sh 0000:00:1f.3
setpci -s 0000:00:1f.3 00=86 01=80 02=c8 03=a0 04=06 05=04 06=10 07=00 08=20 09=00 0a=01 0b=04 0c=10 0d=20 0e=00 0f=00
setpci -s 0000:00:1f.3 10=04 11=00 12=2d 13=3f 14=60 15=00 16=00 17=00 18=00 19=00 1a=00 1b=00 1c=00 1d=00 1e=00 1f=00
setpci -s 0000:00:1f.3 20=04 21=00 22=00 23=3f 24=60 25=00 26=00 27=00 28=00 29=00 2a=00 2b=00 2c=43 2d=10 2e=22 2f=1a
setpci -s 0000:00:1f.3 30=00 31=00 32=00 33=00 34=50 35=00 36=00 37=00 38=00 39=00 3a=00 3b=00 3c=ff 3d=01 3e=00 3f=00
setpci -s 0000:00:1f.3 40=00 41=00 42=00 43=00 44=10 45=00 46=00 47=00 48=ff 49=09 4a=fb 4b=00 4c=00 4d=00 4e=00 4f=00
setpci -s 0000:00:1f.3 50=01 51=80 52=43 53=c0 54=0b 55=01 56=00 57=00 58=00 59=00 5a=00 5b=00 5c=00 5d=00 5e=00 5f=00
setpci -s 0000:00:1f.3 60=05 61=00 62=81 63=00 64=18 65=0b 66=e0 67=fe 68=00 69=00 6a=00 6b=00 6c=00 6d=00 6e=00 6f=00
setpci -s 0000:00:1f.3 70=10 71=00 72=91 73=00 74=00 75=00 76=00 77=10 78=00 79=28 7a=10 7b=00 7c=00 7d=00 7e=00 7f=00
setpci -s 0000:00:1f.3 80=09 81=60 82=14 83=f0 84=10 85=00 86=40 87=01 88=00 89=00 8a=00 8b=00 8c=a1 8d=04 8e=01 8f=00
setpci -s 0000:00:1f.3 90=00 91=08 92=28 93=00 94=00 95=00 96=00 97=00 98=00 99=00 9a=00 9b=00 9c=00 9d=00 9e=00 9f=00
setpci -s 0000:00:1f.3 a0=00 a1=00 a2=00 a3=00 a4=00 a5=00 a6=00 a7=00 a8=00 a9=00 aa=00 ab=00 ac=00 ad=00 ae=00 af=00
setpci -s 0000:00:1f.3 b0=00 b1=00 b2=00 b3=00 b4=00 b5=00 b6=00 b7=00 b8=00 b9=00 ba=00 bb=00 bc=00 bd=00 be=00 bf=00
setpci -s 0000:00:1f.3 c0=02 c1=06 c2=02 c3=28 c4=00 c5=60 c6=80 c7=04 c8=00 c9=0c ca=a5 cb=82 cc=10 cd=00 ce=03 cf=00
setpci -s 0000:00:1f.3 d0=00 d1=0c d2=b5 d3=02 d4=10 d5=00 d6=03 d7=00 d8=00 d9=00 da=00 db=00 dc=00 dd=00 de=00 df=00
setpci -s 0000:00:1f.3 e0=00 e1=00 e2=00 e3=00 e4=00 e5=00 e6=00 e7=00 e8=00 e9=00 ea=00 eb=00 ec=00 ed=00 ee=00 ef=00
setpci -s 0000:00:1f.3 f0=00 f1=00 f2=00 f3=00 f4=00 f5=00 f6=00 f7=00 f8=b5 f9=0f fa=21 fb=01 fc=00 fd=00 fe=00 ff=00

UNIX 98 pseudoterminals briefly explained

Quite some time ago, I was experimenting with UNIX 98 pseudoterminals. A pseudoterminal is a device (or more specifically, a device pair) that has the same semantics as a regular TTY terminal except that its other end is connected to a process. The device that offers TTY semantics is refered to as the pseudoterminal slave, while the other end is known as the master. In other words, a pseudoterminal can be used to communicate two processes where one of them sees the channel as a TTY. For more information, see pts(4). This is especially useful, e.g. to implement a terminal emulator or a remote login program.

In short, issuing open() on the /dev/ptmx device (PseudoTerminal MultipleXor) results in the creation of a new master-slave device pair. The file descriptor returned by open() refers to the pseudoterminal master; the path to the matching slave end can be obtained via ptsname(). grantpt() should be called before trying to open the slave side in order to set the mode and owner of the device.

Fair enough. I thought that a good exercise would be to combine this with a TCP/IPv4 socket, forwarding traffic between the pseudoterminal master and the socket. In the gist below, select() is also used to wait for incoming data on both ends and two extra pipes + splice() are used to perform zero-copy transfers.

/*
* pseudoterminal_tcp.c - Illustrates how to use UNIX 98 pseudoterminals in
* conjunction with TCP sockets
*
* Copyright (C) 2009 Javier Lopez-Gomez
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Compiler command line: `$ gcc -O2 -Wall -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64
* \ -o pseudoterminal_tcp pseudoterminal_tcp.c`
*/
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/sendfile.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>
#define BIND_ADDR INADDR_LOOPBACK
#define BIND_PORT 2323
#define BACKLOG 50
#define BUF_SIZE 65536
#define SHELL "/bin/bash"
#define FATAL(s) \
do { \
perror(s); \
exit(EXIT_FAILURE); \
} while (0)
#undef max
#define max(a, b) ((a) > (b) ? (a) : (b))
static pid_t _pid_shell;
static _Bool _terminate = 0;
// clang-format off
/// \brief Spawn a process. If `sid != NULL`, the spawned process becomes the leader
/// of a new session and its ID is returned in `*sid`.
/// \param argv An array of pointers to NUL-terminated strings that represent the
/// argument list (see exec(3)).
/// \param fd_stdin (and `fd_(stdout|stderr)`) specify a file descriptor where stdin,
/// stdout and stderr are redirected.
// clang-format on
pid_t spawn_process(char *const argv[], int fd_stdin, int fd_stdout,
int fd_stderr, pid_t *sid) {
pid_t child_pid;
child_pid = fork();
if (child_pid == 0) {
if (sid != NULL && (*sid = setsid()) == (pid_t)-1)
FATAL("setsid");
if (dup2(fd_stdin, STDIN_FILENO) == -1 ||
dup2(fd_stdout, STDOUT_FILENO) == -1 ||
dup2(fd_stderr, STDERR_FILENO) == -1)
FATAL("dup2");
execvp(argv[0], argv);
FATAL("execvp");
}
return child_pid;
}
/// \brief Relay data from / to `fd_tty` and `fd_socket`
void do_relay(int fd_tty, int fd_socket) {
fd_set readfds, writefds, exceptfds;
int pipe_tty2socket[2], pipe_socket2tty[2];
size_t send_count = 0, recv_count = 0;
if (pipe(pipe_tty2socket) == -1)
FATAL("pipe");
if (pipe(pipe_socket2tty) == -1)
FATAL("pipe");
while (!_terminate) {
int r, nfds = 0;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_ZERO(&exceptfds);
FD_SET(fd_tty, &readfds);
FD_SET(fd_socket, &readfds);
FD_SET(fd_tty, &exceptfds);
FD_SET(fd_socket, &exceptfds);
nfds = max(fd_tty, fd_socket);
r = select(nfds + 1, &readfds, &writefds, &exceptfds, NULL);
if (r == -1) {
if (errno == EINTR)
continue;
FATAL("select");
}
if (FD_ISSET(fd_tty, &readfds)) {
// FIXME: a simple `sendfile()` should do the job here; it, however, hangs
// for some reason
r = splice(fd_tty, NULL, pipe_tty2socket[1], NULL, BUF_SIZE,
SPLICE_F_MOVE);
if (r < 1)
break;
splice(pipe_tty2socket[0], NULL, fd_socket, NULL, r, SPLICE_F_MOVE);
send_count += r;
}
if (FD_ISSET(fd_socket, &readfds)) {
r = splice(fd_socket, NULL, pipe_socket2tty[1], NULL, BUF_SIZE,
SPLICE_F_MOVE);
if (r < 1)
break;
splice(pipe_socket2tty[0], NULL, fd_tty, NULL, r,
SPLICE_F_MOVE | SPLICE_F_MOVE);
recv_count += r;
}
fprintf(stderr, "\rUP [%ld bytes] | DOWN [%ld bytes]", send_count,
recv_count);
}
close(pipe_tty2socket[0]);
close(pipe_tty2socket[1]);
close(pipe_socket2tty[0]);
close(pipe_socket2tty[1]);
}
void handle_sigchld(int sig, siginfo_t *info, void *ucontext) {
int wstatus;
if (waitpid(info->si_pid, &wstatus, WNOHANG) == _pid_shell)
_terminate = 1;
}
int main(int argc, char *argv[]) {
struct sigaction sa;
sa.sa_sigaction = &handle_sigchld;
sa.sa_flags = SA_SIGINFO;
sigaction(SIGCHLD, &sa, /*oldact=*/NULL);
int fd_listen, fd_client;
struct sockaddr_in sa_listen, sa_client;
socklen_t sa_client_len;
int fd_ptmx, fd_pts;
char *ptspath;
pid_t sid = 0;
char *const shell_argv[] = {SHELL, NULL};
fd_listen = socket(AF_INET, SOCK_STREAM, 0);
sa_listen.sin_family = AF_INET;
sa_listen.sin_addr.s_addr = htonl(BIND_ADDR);
sa_listen.sin_port = htons(BIND_PORT);
if (bind(fd_listen, (struct sockaddr *)&sa_listen,
sizeof(struct sockaddr_in)) == -1)
FATAL("bind");
if (listen(fd_listen, BACKLOG) == -1)
FATAL("listen");
fprintf(stderr, "listening on %s:%d\n", inet_ntoa(sa_listen.sin_addr),
BIND_PORT);
sa_client_len = sizeof(struct sockaddr_in);
fd_client = accept(fd_listen, (struct sockaddr *)&sa_client, &sa_client_len);
fd_ptmx = open("/dev/ptmx", O_RDWR);
if (grantpt(fd_ptmx) == -1)
FATAL("grantpt");
if (unlockpt(fd_ptmx) == -1)
FATAL("unlockpt");
ptspath = ptsname(fd_ptmx);
fd_pts = open(ptspath, O_RDWR);
_pid_shell = spawn_process(shell_argv, fd_pts, fd_pts, fd_pts, &sid);
fprintf(stderr, "_pid_shell=%d sid=%d ptspath=%s\n", _pid_shell, sid,
ptspath);
do_relay(fd_ptmx, fd_client);
kill(_pid_shell, SIGTERM);
close(fd_ptmx);
shutdown(fd_client, SHUT_RDWR);
close(fd_client);
close(fd_listen);
return EXIT_SUCCESS;
}