From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail.openvz.org (unknown [69.168.225.77]) by lore.virtuozzo.com (Postfix) with ESMTPS id 92EDA802A5 for ; Wed, 7 Oct 2026 11:58:30 +0000 (UTC) Received: from mail.openvz.org (localhost [127.0.0.1]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 697Bv9t7004337; Wed, 7 Oct 2026 14:57:10 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 697Bv9t7004337 Authentication-Results: mail.openvz.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=virtuozzo.com header.i=@virtuozzo.com header.b="elldgVuC" Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 697Bv9MM004321 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=FAIL) for ; Wed, 7 Oct 2026 14:57:09 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 697Bv9MM004321 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-48afe000b94so3330661f8f.3 for ; Wed, 07 Oct 2026 04:57:09 -0700 (PDT) X-Forwarded-Encrypted: i=2; AKwUvBzA++50In6neet9ScRVz7ZhqDg7d1n69SJruUgPwz5uIdqvqFBIypWUWlppcqrDaT/aTLI9kg==@openvz.org X-Gm-Message-State: AFq9FYLCZoCTA7dMvLO1s2vd47KzTCIN3gfZkQjy7B6Oo0Hit1mGUGoR GyzuzQef66FjWUeOht2QbJ4YQQo6xe2dGzuNYV+ZQBQC6AZF7uADIyoTM9IrIPRFsYqVy8wnNXJ pczBQ3WR0tKed7TaOsEZwEQRN9MBHkP3/7ipwLiFGGeyCXVCE7yYf1w== X-Gm-Gg: AYBFou1pmm7YsaOMGj8KbBRqUACjj6n7GQO6HPpVzCBEX7ZpZD88W5N5CIVf1nw449W NKNy+e5TVjCTsuqtPz8Ny3053lCnwo3ehnMfSNosmKF0ZVAgOb+jJzTkirEZh97CTEgOFfNOn3w B+XMqcNMVSTBpyipfDd7gJg49ML51dfe4dMfaSnJ4zcMw33+PsEL8AztGM+21b0zhEIfFoVVF6B TdjBvYByDh6/Mqw3dMNqalpco0Ig6CUQ4qiRU53DXw+p5RxdDLB5xP64U1i6lbWWHejzrjKXOY8 w4Uc+Mnn79VlKqj8sNbBQsOtdgyBl8Iv6C2V2PndlkjpRHaKQHW5B/2yTAMDHMbmvKirXFZfw2R PurjLkDANy3lEkppiyA== X-Received: by 2002:a05:6000:25f6:b0:48c:67d6:a87a with SMTP id ffacd0b85a97d-48c72786a1emr4199089f8f.32.1791374228495; Wed, 07 Oct 2026 04:57:08 -0700 (PDT) X-Received: by 2002:a05:6000:25f6:b0:48c:67d6:a87a with SMTP id ffacd0b85a97d-48c72786a1emr4199024f8f.32.1791374227848; Wed, 07 Oct 2026 04:57:07 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1791374227; cv=none; d=google.com; s=arc-20260327; b=f32dgPnnCpNChQzmoOfyR0iIRyPkt1vyzQHI/72SPmYfqfSE7DdpLLSBg1Q/vSaTZs Bb400o4odO+1sUYt6393qa1AqL4ev6nv1i53jiozPduXnVeoOX65XjSLGl1Ay0A5r7s5 NUIVNdDS5ArKNQKaHSaAS6wfDSy+pYZ3Z2ffyRpsvIc7GblzGxlkrLITglk2i+Frfk9i RbjsXuMXbEImNAUAB4OilCwmTeu3iIvvFpKBfJUSeuLGBcG3iaVzh/CCXcenGEBj+DLL J9+sw0TUgCxt2RE5AKxFLH+Ew8cayqfwcNRzOZzHMe7rg+4SHgIOAdb59Z7e1ZAyWlMd Hs+g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:dkim-signature; bh=VnOA9EwjTrNrvioI7V6vNeMtYCSk9CMFSyEaBSxgQA8=; fh=bRkZfFa6377EgOVW8zBDri2gGIQqe/ZeiH+ijEM/ROI=; b=gkabH+dVpxfeYAvJRXWd5R7Zu2T8A8YRW4vTUlyWtDSIbssuT829W51GqiRKbq0pFe o893sqkSXi9G5BBib7kD3aNsSAXjSRVhIaZEyICTf77xsFQH3ZVdRDxiY20M13lD3bdn 1iT8Ph8CCnwIH9EWQ+1+kdO0NFqtOsq7XwEiig6FT4ZUbUWH3pP2+zwLjKewld5rPfsY 2U2bCO5cl8yU9J2CxVzlbqyl7bxFYoaVj0AHfRc1sgRvpr0lIOV3wvCn86mP8FhN1iRv hPeP70v2VSnUOH6RQxYON+b0ubghYRIyRKTUmMDzi3onx3xOrMIzeccVvCSjcIMbSMWK GTzg==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b=elldgVuC; spf=pass (google.com: domain of khorenko@virtuozzo.com designates 130.117.225.111 as permitted sender) smtp.mailfrom=khorenko@virtuozzo.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=virtuozzo.com Received: from relay.virtuozzo.com (relay.virtuozzo.com. [130.117.225.111]) by mx.google.com with ESMTPS id ffacd0b85a97d-48c724a3204si4844471f8f.335.2026.10.07.04.57.07 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 07 Oct 2026 04:57:07 -0700 (PDT) Received-SPF: pass (google.com: domain of khorenko@virtuozzo.com designates 130.117.225.111 as permitted sender) client-ip=130.117.225.111; Authentication-Results: mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b=elldgVuC; spf=pass (google.com: domain of khorenko@virtuozzo.com designates 130.117.225.111 as permitted sender) smtp.mailfrom=khorenko@virtuozzo.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=virtuozzo.com DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=virtuozzo.com; s=relay; h=Message-Id:Content-Type:MIME-Version:Subject:Date :From; bh=VnOA9EwjTrNrvioI7V6vNeMtYCSk9CMFSyEaBSxgQA8=; b=elldgVuC/f+ljMYNuVN dGq8Ugt3ONQW5bRvKXqKoLWLUOYA0StKHNCXAxhg9FiFcao8FL7a3uYEJ8MCuWqNZ0y+OHoGPsY/S F3Dd6FWXOvcdlwcNv1Bo39yALv9q0EB08oOBDeLMhL+wqx7Ft9+raz0TuyZWg35CrN6vykNBRt0vZ JcPEnWaRH2c67lmN0klTDgvsb5UW+ae3Ju2hMmWxrml/jQV/NvUgE1HQsIaLUSVOpRrf4Kb5F5efu emkm7qglOerELdUwRvZc6ivfTFkdKf5pgEpfFFooYMt9fFfGQxhezHKopwxuD4ldBTnY2SLxQsF0x kVI6NWMRBsRx8Fg==; Received: from ch-demo-asa.virtuozzo.com ([130.117.225.8] helo=f0.sw.ru) by relay.virtuozzo.com with esmtp (Exim 4.96) (envelope-from ) id 1xEQDR-002m3X-0w; Wed, 07 Oct 2026 13:57:06 +0200 From: Konstantin Khorenko Date: Wed, 07 Oct 2026 13:57:02 +0200 MIME-Version: 1.0 Message-Id: <20261007-b4-prep-khorenko-vstor-148656-cpuid-v6-1-a8eb906e69b8@virtuozzo.com> References: <20261007-b4-prep-khorenko-vstor-148656-cpuid-v6-0-a8eb906e69b8@virtuozzo.com> In-Reply-To: <20261007-b4-prep-khorenko-vstor-148656-cpuid-v6-0-a8eb906e69b8@virtuozzo.com> To: Pavel Tikhomirov , Vasileios Almpanis X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=12695; i=khorenko@virtuozzo.com; h=from:subject:message-id; bh=+QKiM1rJNOkGOb7lsObfntV+7pvxnfuGY0iZbqemIDg=; b=owEBbQKS/ZANAwAKAVGWCkf5YVwqAcsmYgBqxjORBlnQoyXDbXEil8SftBcWu+pwHPIkTCLd5 hewhRqugW+JAjMEAAEKAB0WIQRWD23IPcXT0GO9CCxRlgpH+WFcKgUCasYzkQAKCRBRlgpH+WFc KqC2D/4/eWqmyaD6+RjuUoLuRFq6hJuykspaT8Hqt9uMQUJvbmF/6hAS+HYLDH0QXTi4SdipCwG RtuYX2D0s4FMiFA+Ycec5/F6gSANdHzknglYqPauf8OAxDKDhIPC+ecuBf4bd15iVm+lO4ZecYA iBZniyBqYGnBcu+Sbo7Nn0IFbbUldxMR+WXSJ/VKLS4rb4Kwd4F3TjaagR6PZ90323Kjr85cCuV yXXML2ufVfEKC4hZhNyxTjgatwVV6fhPUsankQL9bx5ML3W3R1ijJQKPThImxG1XNWiJtxOrfbx KwAq0a/trIY/EqLPPcVmTZD0f5s8qYVKUjI/YyZwIGpGO+2jWfrNZ3X5TjejSXWdVkbx1G3iCcl v3rosdp797traCcwE7ttlxlM/uxvglM9x28aE2iXrwKs0NS7sLvjAPmKYjCjz+hZ/CH2gKhRq3F 2Hm/sohv9lQ+UB3yLwuY2i08t3A5GCmBAsgUUTICx6neT66itr/OnUcVzjdmiDt18n8k/sSMiKv XTO9u22QrCC3QXWKxZQ7N5Srxe1nK857NuDri8GR0YxBkbCoSzRGYYT0yUaepAEVugubafV/X8A kTpr2fWD++SEfkWczjDs601LcVJsXbGSIDkU2+rsq33ZHJ8SvVr7Q9LL1z1hoGR8AqiJ9HHsSuU ECYFqORCNeCJnXQ== X-Developer-Key: i=khorenko@virtuozzo.com; a=openpgp; fpr=560F6DC83DC5D3D063BD082C51960A47F9615C2A X-OZ-Fwd: true Cc: devel@openvz.org Subject: [Devel] [PATCH hci-8.1 v6 1/5] selftests/ve: check CPUID override emulation for VE tasks X-BeenThere: devel@openvz.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: OpenVZ development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: devel-bounces@openvz.org Errors-To: devel-bounces@openvz.org Write a one-entry /proc/vz/cpuid_override table that clears one leaf 1 feature bit and compare what a task in a fresh VE and the host see: the VE task must get the table values, the host must keep the hardware bit. A second test flushes the table after the task was armed and expects the hardware bit back, since faulting stays on for the task and the emulation has to fall back to the real CPUID. On its own that test would also pass on a kernel that never arms faulting; the first one proves the arming. Faulting is switched on for a task at its next context switch, not when the flag is set, so the child stops itself with SIGSTOP after entering the VE and the parent resumes it before the CPUID. The stop is reported to the parent before the child leaves the CPU, and a SIGCONT in that window would let it run on without a switch, so the child hands over its voluntary context switch count first and the parent waits for it to grow before the SIGCONT. Any switch after that count was taken arms faulting on the way back in, so it does not matter whether the stop or an earlier sleep is the one counted. For the second test the table is flushed while the child stands still. Without commit 07338fbae5a3 ("x86/traps: emulate CPUID faults for user tasks in exc_general_protection()") both children die with SIGSEGV. The tests skip on CPUs without CPUID faulting and restore the previous table on exit; a table the kernel cannot take back in one write fails the setup instead. The harness may skip FIXTURE_TEARDOWN once an ASSERT has fired, so the cleanup is a FIXTURE_TEARDOWN_PARENT, which runs exactly once whether or not one did; it also kills a child that such an ASSERT left stopped in the VE cgroup. The test is built on x86-64 only. https://virtuozzo.atlassian.net/browse/VSTOR-148843 Feature: x86: cpu pools (cpuid override) Signed-off-by: Konstantin Khorenko --- tools/testing/selftests/ve/.gitignore | 1 + tools/testing/selftests/ve/Makefile | 6 + .../testing/selftests/ve/ve_cpuid_override_test.c | 298 +++++++++++++++++++++ 3 files changed, 305 insertions(+) diff --git a/tools/testing/selftests/ve/.gitignore b/tools/testing/selftests/ve/.gitignore index 3df4d05888dce..bdc322c645d95 100644 --- a/tools/testing/selftests/ve/.gitignore +++ b/tools/testing/selftests/ve/.gitignore @@ -1,3 +1,4 @@ ve_ns_owner_test ve_perms_test ve_mount_accounting_test +ve_cpuid_override_test diff --git a/tools/testing/selftests/ve/Makefile b/tools/testing/selftests/ve/Makefile index c6efe7c4b4fba..3f494a49270e5 100644 --- a/tools/testing/selftests/ve/Makefile +++ b/tools/testing/selftests/ve/Makefile @@ -6,4 +6,10 @@ TEST_GEN_PROGS += ve_ns_owner_test TEST_GEN_PROGS += ve_perms_test TEST_GEN_PROGS += ve_mount_accounting_test +# CPUID faulting is x86-64 only. ARCH says "x86" for 32-bit too and lib.mk +# picks the clang target by its emptiness, so decide by the compiler. +ifneq ($(filter x86_64-%,$(shell $(CC) -dumpmachine 2>/dev/null)),) +TEST_GEN_PROGS += ve_cpuid_override_test +endif + include ../lib.mk diff --git a/tools/testing/selftests/ve/ve_cpuid_override_test.c b/tools/testing/selftests/ve/ve_cpuid_override_test.c new file mode 100644 index 0000000000000..a56e0c7213fb9 --- /dev/null +++ b/tools/testing/selftests/ve/ve_cpuid_override_test.c @@ -0,0 +1,298 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * /proc/vz/cpuid_override selftests + * + * A non-empty override table turns CPUID faulting on for every task that + * enters a VE, and the #GP handler has to emulate the instruction for + * them. The tests check that a task in a VE sees the table values, that + * the host keeps seeing the hardware values, and that a task which was + * armed while the table was set falls back to the hardware once the + * table is flushed. A kernel that does not emulate the fault kills the + * child with SIGSEGV instead. + * + * The table is global: run this on a node without live Containers and one + * instance at a time, a task entering a VE while a case runs is armed for + * life. A harness timeout kills the test without its teardown and leaves + * the test table in place and the VE cgroup behind. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../kselftest_harness.h" +#include "ve_selftest.h" + +#define CPUID_OVERRIDE_PATH "/proc/vz/cpuid_override" +#define CPUID_LEAF 1 +#define CPUID_LINE_LEN 128 +/* The kernel takes a table back only in one write below a page. */ +#define CPUID_WRITE_MAX 4096 +#define CPUID_SAVED_MAX (CPUID_WRITE_MAX + 1) +#define SWITCH_WAIT_ROUNDS 100000 + +struct cpuid_regs { + unsigned int eax, ebx, ecx, edx; +}; + +static void do_cpuid(unsigned int leaf, struct cpuid_regs *r) +{ + __cpuid_count(leaf, 0, r->eax, r->ebx, r->ecx, r->edx); +} + +/* Voluntary context switches of a task, from its /proc status file. */ +static int read_nvcsw(const char *status, unsigned long *nvcsw) +{ + char buf[8192], *p; + + if (read_file_at(AT_FDCWD, status, buf, sizeof(buf)) <= 0) + return -1; + p = strstr(buf, "\nvoluntary_ctxt_switches:"); + if (!p || sscanf(p, "\nvoluntary_ctxt_switches: %lu", nvcsw) != 1) + return -1; + return 0; +} + +struct child_ctx { + int result_pipe[2]; +}; + +/* + * The child enters a fresh VE, so it is armed with the table state of that + * moment, then reports its view of the leaf to the parent over a pipe. It + * stops itself in between: a stopped task is off the CPU, so the resume is + * a context switch, and the parent may change the table while the child + * stands still. It tells the parent its context switch count first, so + * that the parent can wait for the switch out. + */ +static int cpuid_child(struct child_ctx *ctx) +{ + struct cpuid_regs r; + unsigned long nvcsw; + + close(ctx->result_pipe[0]); + + if (unshare(CLONE_NEWVE) < 0) + return 21; + if (read_nvcsw("/proc/self/status", &nvcsw)) + return 22; + if (write(ctx->result_pipe[1], &nvcsw, sizeof(nvcsw)) != sizeof(nvcsw)) + return 23; + if (raise(SIGSTOP)) + return 24; + + do_cpuid(CPUID_LEAF, &r); + + if (write(ctx->result_pipe[1], &r, sizeof(r)) != sizeof(r)) + return 25; + return 0; +} + +FIXTURE(ve_cpuid_override) +{ + int cgv2_fd; + int ctid; + struct cpuid_regs host; + unsigned int bit; + pid_t child; + char table[CPUID_LINE_LEN]; + char saved[CPUID_SAVED_MAX]; +}; + +FIXTURE_SETUP(ve_cpuid_override) +{ + int fd, len; + + if (geteuid()) + SKIP(return, "needs root"); + fd = open(CPUID_OVERRIDE_PATH, O_RDONLY); + if (fd < 0) + SKIP(return, "%s: %s", CPUID_OVERRIDE_PATH, strerror(errno)); + close(fd); + + len = read_file_at(AT_FDCWD, CPUID_OVERRIDE_PATH, self->saved, + sizeof(self->saved)); + ASSERT_GE(len, 0) TH_LOG("%s: %s", CPUID_OVERRIDE_PATH, strerror(errno)); + ASSERT_LT(len, CPUID_WRITE_MAX) + TH_LOG("a table of at least %d bytes cannot be restored", len); + + /* Mask one feature bit the host has; SSE2 when present. */ + do_cpuid(CPUID_LEAF, &self->host); + self->bit = 1u << 26; + if (!(self->host.edx & self->bit)) + self->bit = self->host.edx & -self->host.edx; + ASSERT_NE(self->bit, 0u); + + snprintf(self->table, sizeof(self->table), + "0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n", CPUID_LEAF, + self->host.eax, self->host.ebx, self->host.ecx, + self->host.edx & ~self->bit); + + /* Last, so that a failed ASSERT above leaves no VE cgroup behind. */ + self->cgv2_fd = mount_cg2_fd(); + ASSERT_GE(self->cgv2_fd, 0) TH_LOG("cgroup2 mount: %s", strerror(errno)); + ASSERT_EQ(write_file_at(self->cgv2_fd, "cgroup.subtree_control", + VE_CONTROLLERS), 0); + self->ctid = make_ve(self->cgv2_fd, CTID_MIN); + ASSERT_GE(self->ctid, 0); +} + +/* + * Runs after the test body in whichever process the harness picks, the test + * process itself after a failed ASSERT, so the table is restored whether or + * not one fired. The setup fd may be gone by then, hence the fresh mount. + */ +FIXTURE_TEARDOWN_PARENT(ve_cpuid_override) +{ + int cgv2_fd; + + EXPECT_EQ(write_file_at(AT_FDCWD, CPUID_OVERRIDE_PATH, + self->saved[0] ? self->saved : "\n"), 0) + TH_LOG("could not restore %s: %s", CPUID_OVERRIDE_PATH, + strerror(errno)); + + /* A child left stopped by a failed ASSERT keeps the VE cgroup busy. */ + if (self->child > 0) + kill(self->child, SIGKILL); + + cgv2_fd = mount_cg2_fd(); + if (cgv2_fd < 0) { + TH_LOG("cgroup2 mount: %s, VE cgroup %d left behind", + strerror(errno), self->ctid); + return; + } + destroy_ve(cgv2_fd, self->ctid); + close(cgv2_fd); +} + +/* + * Stopped is reported to the parent before the child leaves the CPU, so a + * SIGCONT sent right away could keep it running without a switch. Wait + * until its voluntary context switch count has moved on: any switch after + * the count was taken, which is after the flag was set, arms faulting on + * the way back in, whether it is the stop or an earlier sleep. + */ +static void wait_switched_out(struct __test_metadata *_metadata, pid_t pid, + unsigned long nvcsw_before) +{ + char status[64]; + unsigned long nvcsw; + int i; + + snprintf(status, sizeof(status), "/proc/%d/status", pid); + for (i = 0; i < SWITCH_WAIT_ROUNDS; i++) { + ASSERT_EQ(read_nvcsw(status, &nvcsw), 0); + if (nvcsw > nvcsw_before) + return; + sched_yield(); + } + ASSERT_GT(nvcsw, nvcsw_before); +} + +/* Fork the child into the VE and return once it is off the CPU. */ +static pid_t spawn_cpuid_child(struct __test_metadata *_metadata, + FIXTURE_DATA(ve_cpuid_override) * self, + struct child_ctx *ctx) +{ + unsigned long nvcsw; + int status; + pid_t pid; + + ASSERT_EQ(pipe(ctx->result_pipe), 0); + ASSERT_GE(enter_cgroup(self->cgv2_fd, self->ctid), 0); + + pid = fork(); + if (pid == 0) + _exit(cpuid_child(ctx)); + if (pid > 0) + self->child = pid; + + /* Leave the VE cgroup before any ASSERT, or destroy_ve() gets EBUSY. */ + ASSERT_GE(enter_cgroup(self->cgv2_fd, 0), 0); + ASSERT_GE(pid, 0); + close(ctx->result_pipe[1]); + + ASSERT_GE(waitpid(pid, &status, WUNTRACED), 0); + if (!WIFSTOPPED(status)) { + /* Reaped: the pid may be reused, keep it from teardown. */ + self->child = 0; + if (WIFEXITED(status)) + TH_LOG("child exited with %d", WEXITSTATUS(status)); + if (WIFSIGNALED(status)) + TH_LOG("child killed by signal %d", WTERMSIG(status)); + } + ASSERT_TRUE(WIFSTOPPED(status)); + ASSERT_EQ(read(ctx->result_pipe[0], &nvcsw, sizeof(nvcsw)), + (int)sizeof(nvcsw)); + wait_switched_out(_metadata, pid, nvcsw); + return pid; +} + +static void resume_cpuid_child(struct __test_metadata *_metadata, pid_t pid) +{ + ASSERT_EQ(kill(pid, SIGCONT), 0); +} + +static void collect_cpuid_child(struct __test_metadata *_metadata, + FIXTURE_DATA(ve_cpuid_override) * self, + struct child_ctx *ctx, struct cpuid_regs *r) +{ + int status, len; + + len = read(ctx->result_pipe[0], r, sizeof(*r)); + ASSERT_GE(waitpid(self->child, &status, 0), 0); + self->child = 0; + if (WIFSIGNALED(status)) + TH_LOG("child killed by signal %d", WTERMSIG(status)); + ASSERT_TRUE(WIFEXITED(status)); + ASSERT_EQ(WEXITSTATUS(status), 0); + ASSERT_EQ(len, (int)sizeof(*r)); + + close(ctx->result_pipe[0]); +} + +TEST_F(ve_cpuid_override, ve_sees_table_host_sees_hardware) +{ + struct child_ctx ctx; + struct cpuid_regs r; + pid_t pid; + + ASSERT_EQ(write_file_at(AT_FDCWD, CPUID_OVERRIDE_PATH, self->table), 0); + + pid = spawn_cpuid_child(_metadata, self, &ctx); + resume_cpuid_child(_metadata, pid); + collect_cpuid_child(_metadata, self, &ctx, &r); + + EXPECT_EQ(r.eax, self->host.eax); + EXPECT_EQ(r.ebx, self->host.ebx); + EXPECT_EQ(r.ecx, self->host.ecx); + EXPECT_EQ(r.edx, self->host.edx & ~self->bit); + + do_cpuid(CPUID_LEAF, &r); + EXPECT_NE(r.edx & self->bit, 0u); +} + +TEST_F(ve_cpuid_override, flushed_table_falls_back_to_hardware) +{ + struct child_ctx ctx; + struct cpuid_regs r; + pid_t pid; + + ASSERT_EQ(write_file_at(AT_FDCWD, CPUID_OVERRIDE_PATH, self->table), 0); + + pid = spawn_cpuid_child(_metadata, self, &ctx); + + ASSERT_EQ(write_file_at(AT_FDCWD, CPUID_OVERRIDE_PATH, "\n"), 0); + resume_cpuid_child(_metadata, pid); + collect_cpuid_child(_metadata, self, &ctx, &r); + + EXPECT_NE(r.edx & self->bit, 0u); +} + +TEST_HARNESS_MAIN -- 2.43.0 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel