Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/dom/xml/crashtests/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 241 B image not shown  

Quelle  get-reg-list.c   Sprache: unbekannt

 
// SPDX-License-Identifier: GPL-2.0
/*
 * Check for KVM_GET_REG_LIST regressions.
 *
 * Copyright (C) 2020, Red Hat, Inc.
 *
 * When attempting to migrate from a host with an older kernel to a host
 * with a newer kernel we allow the newer kernel on the destination to
 * list new registers with get-reg-list. We assume they'll be unused, at
 * least until the guest reboots, and so they're relatively harmless.
 * However, if the destination host with the newer kernel is missing
 * registers which the source host with the older kernel has, then that's
 * a regression in get-reg-list. This test checks for that regression by
 * checking the current list against a blessed list. We should never have
 * missing registers, but if new ones appear then they can probably be
 * added to the blessed list. A completely new blessed list can be created
 * by running the test with the --list command line argument.
 *
 * The blessed list should be created from the oldest possible kernel.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "kvm_util.h"
#include "test_util.h"
#include "processor.h"

static struct kvm_reg_list *reg_list;
static __u64 *blessed_reg, blessed_n;

extern struct vcpu_reg_list *vcpu_configs[];
extern int vcpu_configs_n;

#define for_each_reg(i)        \
 for ((i) = 0; (i) < reg_list->n; ++(i))

#define for_each_reg_filtered(i)      \
 for_each_reg(i)        \
  if (!filter_reg(reg_list->reg[i]))

#define for_each_missing_reg(i)       \
 for ((i) = 0; (i) < blessed_n; ++(i))     \
  if (!find_reg(reg_list->reg, reg_list->n, blessed_reg[i])) \
   if (check_supported_reg(vcpu, blessed_reg[i]))

#define for_each_new_reg(i)       \
 for_each_reg_filtered(i)      \
  if (!find_reg(blessed_reg, blessed_n, reg_list->reg[i]))

#define for_each_present_blessed_reg(i)      \
 for_each_reg(i)        \
  if (find_reg(blessed_reg, blessed_n, reg_list->reg[i]))

static const char *config_name(struct vcpu_reg_list *c)
{
 struct vcpu_reg_sublist *s;
 int len = 0;

 if (c->name)
  return c->name;

 for_each_sublist(c, s)
  len += strlen(s->name) + 1;

 c->name = malloc(len);

 len = 0;
 for_each_sublist(c, s) {
  if (!strcmp(s->name, "base"))
   continue;
  if (len)
   c->name[len++] = '+';
  strcpy(c->name + len, s->name);
  len += strlen(s->name);
 }
 c->name[len] = '\0';

 return c->name;
}

bool __weak check_supported_reg(struct kvm_vcpu *vcpu, __u64 reg)
{
 return true;
}

bool __weak filter_reg(__u64 reg)
{
 return false;
}

static bool find_reg(__u64 regs[], __u64 nr_regs, __u64 reg)
{
 int i;

 for (i = 0; i < nr_regs; ++i)
  if (reg == regs[i])
   return true;
 return false;
}

void __weak print_reg(const char *prefix, __u64 id)
{
 printf("\t0x%llx,\n", id);
}

bool __weak check_reject_set(int err)
{
 return true;
}

void __weak finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c)
{
}

#ifdef __aarch64__
static void prepare_vcpu_init(struct vcpu_reg_list *c, struct kvm_vcpu_init *init)
{
 struct vcpu_reg_sublist *s;

 for_each_sublist(c, s)
  if (s->capability)
   init->features[s->feature / 32] |= 1 << (s->feature % 32);
}

static struct kvm_vcpu *vcpu_config_get_vcpu(struct vcpu_reg_list *c, struct kvm_vm *vm)
{
 struct kvm_vcpu_init init = { .target = -1, };
 struct kvm_vcpu *vcpu;

 prepare_vcpu_init(c, &init);
 vcpu = __vm_vcpu_add(vm, 0);
 aarch64_vcpu_setup(vcpu, &init);

 return vcpu;
}
#else
static struct kvm_vcpu *vcpu_config_get_vcpu(struct vcpu_reg_list *c, struct kvm_vm *vm)
{
 return __vm_vcpu_add(vm, 0);
}
#endif

static void check_supported(struct vcpu_reg_list *c)
{
 struct vcpu_reg_sublist *s;

 for_each_sublist(c, s) {
  if (!s->capability)
   continue;

  __TEST_REQUIRE(kvm_has_cap(s->capability),
          "%s: %s not available, skipping tests",
          config_name(c), s->name);
 }
}

static bool print_list;
static bool print_filtered;

static void run_test(struct vcpu_reg_list *c)
{
 int new_regs = 0, missing_regs = 0, i, n;
 int failed_get = 0, failed_set = 0, failed_reject = 0;
 int skipped_set = 0;
 struct kvm_vcpu *vcpu;
 struct kvm_vm *vm;
 struct vcpu_reg_sublist *s;

 check_supported(c);

 vm = vm_create_barebones();
 vcpu = vcpu_config_get_vcpu(c, vm);
 finalize_vcpu(vcpu, c);

 reg_list = vcpu_get_reg_list(vcpu);

 if (print_list || print_filtered) {
  putchar('\n');
  for_each_reg(i) {
   __u64 id = reg_list->reg[i];
   if ((print_list && !filter_reg(id)) ||
       (print_filtered && filter_reg(id)))
    print_reg(config_name(c), id);
  }
  putchar('\n');
  return;
 }

 for_each_sublist(c, s)
  blessed_n += s->regs_n;
 blessed_reg = calloc(blessed_n, sizeof(__u64));

 n = 0;
 for_each_sublist(c, s) {
  for (i = 0; i < s->regs_n; ++i)
   blessed_reg[n++] = s->regs[i];
 }

 /*
 * We only test that we can get the register and then write back the
 * same value. Some registers may allow other values to be written
 * back, but others only allow some bits to be changed, and at least
 * for ID registers set will fail if the value does not exactly match
 * what was returned by get. If registers that allow other values to
 * be written need to have the other values tested, then we should
 * create a new set of tests for those in a new independent test
 * executable.
 *
 * Only do the get/set tests on present, blessed list registers,
 * since we don't know the capabilities of any new registers.
 */

 for_each_present_blessed_reg(i) {
  uint8_t addr[2048 / 8];
  struct kvm_one_reg reg = {
   .id = reg_list->reg[i],
   .addr = (__u64)&addr,
  };
  bool reject_reg = false, skip_reg = false;
  int ret;

  ret = __vcpu_get_reg(vcpu, reg_list->reg[i], &addr);
  if (ret) {
   printf("%s: Failed to get ", config_name(c));
   print_reg(config_name(c), reg.id);
   putchar('\n');
   ++failed_get;
  }

  for_each_sublist(c, s) {
   /* rejects_set registers are rejected for set operation */
   if (s->rejects_set && find_reg(s->rejects_set, s->rejects_set_n, reg.id)) {
    reject_reg = true;
    ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, ®);
    if (ret != -1 || !check_reject_set(errno)) {
     printf("%s: Failed to reject (ret=%d, errno=%d) ", config_name(c), ret, errno);
     print_reg(config_name(c), reg.id);
     putchar('\n');
     ++failed_reject;
    }
    break;
   }

   /* skips_set registers are skipped for set operation */
   if (s->skips_set && find_reg(s->skips_set, s->skips_set_n, reg.id)) {
    skip_reg = true;
    ++skipped_set;
    break;
   }
  }

  if (!reject_reg && !skip_reg) {
   ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, ®);
   if (ret) {
    printf("%s: Failed to set ", config_name(c));
    print_reg(config_name(c), reg.id);
    putchar('\n');
    ++failed_set;
   }
  }
 }

 for_each_new_reg(i)
  ++new_regs;

 for_each_missing_reg(i)
  ++missing_regs;

 if (new_regs || missing_regs) {
  n = 0;
  for_each_reg_filtered(i)
   ++n;

  printf("%s: Number blessed registers: %5lld\n", config_name(c), blessed_n);
  printf("%s: Number registers:         %5lld (includes %lld filtered registers)\n",
         config_name(c), reg_list->n, reg_list->n - n);
 }

 if (new_regs) {
  printf("\n%s: There are %d new registers.\n"
         "Consider adding them to the blessed reg "
         "list with the following lines:\n\n", config_name(c), new_regs);
  for_each_new_reg(i)
   print_reg(config_name(c), reg_list->reg[i]);
  putchar('\n');
 }

 if (missing_regs) {
  printf("\n%s: There are %d missing registers.\n"
         "The following lines are missing registers:\n\n", config_name(c), missing_regs);
  for_each_missing_reg(i)
   print_reg(config_name(c), blessed_reg[i]);
  putchar('\n');
 }

 TEST_ASSERT(!missing_regs && !failed_get && !failed_set && !failed_reject,
      "%s: There are %d missing registers; %d registers failed get; "
      "%d registers failed set; %d registers failed reject; %d registers skipped set",
      config_name(c), missing_regs, failed_get, failed_set, failed_reject, skipped_set);

 pr_info("%s: PASS\n", config_name(c));
 blessed_n = 0;
 free(blessed_reg);
 free(reg_list);
 kvm_vm_free(vm);
}

static void help(void)
{
 struct vcpu_reg_list *c;
 int i;

 printf(
 "\n"
 "usage: get-reg-list [--config=<selection>] [--list] [--list-filtered]\n\n"
 " --config=<selection>        Used to select a specific vcpu configuration for the test/listing\n"
 "                             '<selection>' may be\n");

 for (i = 0; i < vcpu_configs_n; ++i) {
  c = vcpu_configs[i];
  printf(
 "                               '%s'\n", config_name(c));
 }

 printf(
 "\n"
 " --list                      Print the register list rather than test it (requires --config)\n"
 " --list-filtered             Print registers that would normally be filtered out (requires --config)\n"
 "\n"
 );
}

static struct vcpu_reg_list *parse_config(const char *config)
{
 struct vcpu_reg_list *c = NULL;
 int i;

 if (config[8] != '=')
  help(), exit(1);

 for (i = 0; i < vcpu_configs_n; ++i) {
  c = vcpu_configs[i];
  if (strcmp(config_name(c), &config[9]) == 0)
   break;
 }

 if (i == vcpu_configs_n)
  help(), exit(1);

 return c;
}

int main(int ac, char **av)
{
 struct vcpu_reg_list *c, *sel = NULL;
 int i, ret = 0;
 pid_t pid;

 for (i = 1; i < ac; ++i) {
  if (strncmp(av[i], "--config"8) == 0)
   sel = parse_config(av[i]);
  else if (strcmp(av[i], "--list") == 0)
   print_list = true;
  else if (strcmp(av[i], "--list-filtered") == 0)
   print_filtered = true;
  else if (strcmp(av[i], "--help") == 0 || strcmp(av[1], "-h") == 0)
   help(), exit(0);
  else
   help(), exit(1);
 }

 if (print_list || print_filtered) {
  /*
 * We only want to print the register list of a single config.
 */

  if (!sel)
   help(), exit(1);
 }

 for (i = 0; i < vcpu_configs_n; ++i) {
  c = vcpu_configs[i];
  if (sel && c != sel)
   continue;

  pid = fork();

  if (!pid) {
   run_test(c);
   exit(0);
  } else {
   int wstatus;
   pid_t wpid = wait(&wstatus);
   TEST_ASSERT(wpid == pid && WIFEXITED(wstatus), "wait: Unexpected return");
   if (WEXITSTATUS(wstatus) && WEXITSTATUS(wstatus) != KSFT_SKIP)
    ret = KSFT_FAIL;
  }
 }

 return ret;
}

Messung V0.5 in Prozent
C=99 H=89 G=94

[zur Elbe Produktseite wechseln0.44QuellennavigatorsAnalyse erneut starten2026-06-08]