Recently, when ptrace-ing code, I found that the LBT register ftop is always zero, even thought the ptrace-d code sets ftop to non-zero. So I suspect ftop is not correctly maintained across context switches. I wrote the following code to verify my assumption: #include <assert.h> #include <unistd.h> #include <stdio.h> int main() { int b; for(int i = 0;;i++) { printf("loop %d\n", i); // set __asm__("x86mttop 0"); // get __asm__("x86mftop %0" : "=r"(b)); assert(b == 0); usleep(100000); // get again __asm__("x86mftop %0" : "=r"(b)); assert(b == 0); // set __asm__("x86mttop 1"); // get __asm__("x86mftop %0" : "=r"(b)); assert(b == 1); usleep(100000); // get again __asm__("x86mftop %0" : "=r"(b)); assert(b == 1); } } The code snippet sets and gets ftop in a loop, calls to usleep() is added to trigger context switch. The program will fail in several iterations: loop 0 loop 1 loop 2 ftop: ftop.c:32: main: Assertion `b == 1' failed. fish: Job 1, './ftop' terminated by signal SIGABRT (Abort) It might even fail in the first iteration: loop 0 ftop: ftop.c:32: main: Assertion `b == 1' failed. fish: Job 1, './ftop' terminated by signal SIGABRT (Abort) I am using Linux 6.6.0-rc5 with binutils 2.41.0 and gcc 13.2.1.
As pointed out by @spcreply, Linux kernel does not save ftop if tm is not enabled. If asm("x86settm") is added to the code, the ftop is correctly saved and restored across context switching.
The code can be found: [1] https://github.com/torvalds/linux/blob/611da07b89fdd53f140d7b33013f255bf0ed8f34/arch/loongarch/include/asm/asmmacro.h#L46-L48 [2] https://github.com/torvalds/linux/blob/611da07b89fdd53f140d7b33013f255bf0ed8f34/arch/loongarch/include/asm/asmmacro.h#L62-L64