mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [BUG] AMX tile data lost after nanosleep in a Linux guest
@ 2026-09-09 21:13 yoch melka
  2026-09-10 17:28 ` Sean Christopherson
  0 siblings, 1 reply; 2+ messages in thread
From: yoch melka @ 2026-09-09 21:13 UTC (permalink / raw)
  To: x86; +Cc: kvm, linux-kernel


[-- Attachment #1.1: Type: text/plain, Size: 1712 bytes --]

Hi,

I'm seeing AMX tile data silently turn to zero after a 1 ms sleep on a
Linux guest.

The reproducer requests AMX permission, loads a known nonzero pattern into
all eight tiles, calls `nanosleep` through a direct syscall, then stores
and checks the contents. There are no function calls while the tiles are
live; I checked the disassembly with both GCC and Clang.

Build and run on an AMX-capable CPU (replace CPU 0 with an allowed CPU if
necessary):

```
gcc -O2 -g -Wall -Wextra -Werror -mamx-tile -fno-plt amx_min.c -o amx_min

timeout --kill-after=2s 20s taskset -c 0 ./amx_min
timeout --kill-after=2s 20s taskset -c 0 ./amx_min getpid
```

Expected: 0/300 mismatches in both modes.

Observed with GCC 13.3.0: 5/300, 5/300 and 4/300 mismatches in three
`nanosleep` runs. Clang 18.1.3 also reproduces it (3/300). The `getpid`
control was clean in all three control runs (two GCC, one Clang).

The first mismatch reports:
First mismatch: 8192/8192 bytes are zero; TILECFG unchanged

`nanosleep` returns successfully. The failure is intermittent, so a clean
run may need repeating.

Environment:
Ubuntu 24.04, custom Linux 6.12.94+
#1 SMP PREEMPT_DYNAMIC Mon Sep 7 16:15:06 UTC 2026
Intel Xeon, family 6, model 207, stepping 2; 4 vCPUs
KVM reported by the guest; host kernel and VMM unknown

A separate test also loses tile data in a busy loop under CPU contention,
without any syscall while the tiles are live. This suggests an AMX
state-preservation issue around scheduling, but I cannot tell whether the
fault is in the custom guest kernel or the host environment.

Does this resemble a known issue?
Any suggestions for narrowing it down from inside the guest would be
appreciated.

Thanks,
Joshua Melka

[-- Attachment #1.2: Type: text/html, Size: 1846 bytes --]

[-- Attachment #2: amx_min.c --]
[-- Type: text/x-csrc, Size: 2693 bytes --]

/* SPDX-License-Identifier: MIT */
#define _GNU_SOURCE
#include <cpuid.h>
#include <errno.h>
#include <immintrin.h>
#include <stdio.h>
#include <string.h>
#include <sys/syscall.h>
#include <time.h>
#include <unistd.h>

static _Alignas(64) unsigned char cfg[64], cfg_after[64];
static _Alignas(64) unsigned char src[8][1024], dst[8][1024];
static const struct timespec delay = { .tv_nsec = 1000000 };
#define TILES(OP) OP(0); OP(1); OP(2); OP(3); OP(4); OP(5); OP(6); OP(7)
#define LOAD(t) _tile_loadd(t, src[t], 64)
#define STORE(t) _tile_stored(t, dst[t], 64)

/* No function calls from LDTILECFG until TILERELEASE. */
__attribute__((noinline)) long roundtrip(long nr)
{
    _tile_loadconfig(cfg);
    TILES(LOAD);
    long ret;
    __asm__ volatile("syscall" : "=a"(ret)
        : "0"(nr), "D"(&delay), "S"(0L)
        : "rcx", "r11", "memory", "cc");
    _tile_storeconfig(cfg_after);
    for (int i = 0; i < 64; i++) {
        if (cfg[i] != ((volatile unsigned char *)cfg_after)[i]) {
            _tile_release();
            return -4096; /* Configuration changed; do not store tiles. */
        }
    }
    TILES(STORE);
    _mm_mfence();
    _tile_release();
    return ret;
}

int main(int argc, char **argv)
{
    if (argc > 2 || (argc == 2 && strcmp(argv[1], "getpid"))) {
        fprintf(stderr, "Usage: %s [getpid]\n", argv[0]);
        return 2;
    }
    unsigned a, b, c, d;
    if (!__get_cpuid_count(7, 0, &a, &b, &c, &d) || !(d & (1u << 24))) {
        puts("SKIP: AMX_TILE not exposed");
        return 77;
    }
    if (syscall(SYS_arch_prctl, 0x1023 /* ARCH_REQ_XCOMP_PERM */, 18L)) {
        perror("ARCH_REQ_XCOMP_PERM");
        return 77;
    }
    cfg[0] = 1;
    for (int t = 0; t < 8; t++) {
        cfg[16 + 2*t] = 64;
        cfg[48 + t] = 16;
        for (int i = 0; i < 1024; i++)
            src[t][i] = 1 + ((t*1024 + i) % 251);
    }
    int bad = 0;
    for (int n = 0; n < 300; n++) {
        memset(dst, 0xcc, sizeof dst);
        memset(cfg_after, 0xcc, sizeof cfg_after);
        long ret = roundtrip(argc == 2 ? SYS_getpid : SYS_nanosleep);
        if (ret == -4096) { puts("FAIL: TILECFG changed"); return 2; }
        if (ret < 0) { errno = (int)-ret; perror("syscall"); return 2; }
        if (memcmp(src, dst, sizeof src)) {
            if (bad++ == 0) {
                int zeros = 0;
                for (int t = 0; t < 8; t++)
                    for (int i = 0; i < 1024; i++) zeros += dst[t][i] == 0;
                printf("First mismatch: %d/8192 bytes are zero; TILECFG unchanged\n", zeros);
            }
        }
    }
    printf("%d/300 trials lost tile data (%s)\n", bad, argc == 2 ? "getpid" : "nanosleep");
    return bad ? 1 : 0;
}

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-09-10 17:28 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-09 21:13 [BUG] AMX tile data lost after nanosleep in a Linux guest yoch melka
2026-09-10 17:28 ` Sean Christopherson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®