Merge tag 'linux-kselftest-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 28 Oct 2018 19:58:42 +0000 (12:58 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 28 Oct 2018 19:58:42 +0000 (12:58 -0700)
Pull kselftest updates from Shuah Khan:
 "This Kselftest update for Linux 4.20-rc1 consists of:

   - Improvements to ftrace test suite from Masami Hiramatsu.

   - Color coded ftrace PASS / FAIL results from Steven Rostedt (VMware)
     to improve readability of reports.

   - watchdog Fixes and enhancement to add gettimeout and get|set
     pretimeout options from Jerry Hoemann.

   - Several fixes to warnings and spelling etc"

* tag 'linux-kselftest-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: (40 commits)
  selftests/ftrace: Strip escape sequences for log file
  selftests/ftrace: Use colored output when available
  selftests: fix warning: "_GNU_SOURCE" redefined
  selftests: kvm: Fix -Wformat warnings
  selftests/ftrace: Add color to the PASS / FAIL results
  kvm: selftests: fix spelling mistake "Insufficent" -> "Insufficient"
  selftests: gpio: Fix OUTPUT directory in Makefile
  selftests: gpio: restructure Makefile
  selftests: watchdog: Fix ioctl SET* error paths to take oneshot exit path
  selftests: watchdog: Add gettimeout and get|set pretimeout
  selftests: watchdog: Fix error message.
  selftests: watchdog: fix message when /dev/watchdog open fails
  selftests/ftrace: Add ftrace cpumask testcase
  selftests/ftrace: Add wakeup_rt tracer testcase
  selftests/ftrace: Add wakeup tracer testcase
  selftests/ftrace: Add stacktrace ftrace filter command testcase
  selftests/ftrace: Add trace_pipe testcase
  selftests/ftrace: Add function filter on module testcase
  selftests/ftrace: Add max stack tracer testcase
  selftests/ftrace: Add function profiling stat testcase
  ...

1  2 
tools/testing/selftests/kvm/dirty_log_test.c
tools/testing/selftests/kvm/lib/kvm_util.c

index d59820cc2d3981247cd2c2430ad0ef89d11ed2a3,a9c4b5e21d7e7d6f5a1defd58cee478070c6a4b2..aeff95a91b1563b1c81897b18a224dcddf971e10
@@@ -5,8 -5,6 +5,8 @@@
   * Copyright (C) 2018, Red Hat, Inc.
   */
  
 +#define _GNU_SOURCE /* for program_invocation_name */
 +
  #include <stdio.h>
  #include <stdlib.h>
  #include <unistd.h>
  
  #include "test_util.h"
  #include "kvm_util.h"
 +#include "processor.h"
 +
 +#define DEBUG printf
  
 -#define  DEBUG                 printf
 +#define VCPU_ID                               1
  
 -#define  VCPU_ID                        1
  /* The memory slot index to track dirty pages */
 -#define  TEST_MEM_SLOT_INDEX            1
 -/*
 - * GPA offset of the testing memory slot. Must be bigger than the
 - * default vm mem slot, which is DEFAULT_GUEST_PHY_PAGES.
 - */
 -#define  TEST_MEM_OFFSET                (1ULL << 30) /* 1G */
 -/* Size of the testing memory slot */
 -#define  TEST_MEM_PAGES                 (1ULL << 18) /* 1G for 4K pages */
 +#define TEST_MEM_SLOT_INDEX           1
 +
 +/* Default guest test memory offset, 1G */
 +#define DEFAULT_GUEST_TEST_MEM                0x40000000
 +
  /* How many pages to dirty for each guest loop */
 -#define  TEST_PAGES_PER_LOOP            1024
 +#define TEST_PAGES_PER_LOOP           1024
 +
  /* How many host loops to run (one KVM_GET_DIRTY_LOG for each loop) */
- #define TEST_HOST_LOOP_N              32
 -#define  TEST_HOST_LOOP_N               32UL
++#define TEST_HOST_LOOP_N              32UL
 +
  /* Interval for each host loop (ms) */
- #define TEST_HOST_LOOP_INTERVAL               10
 -#define  TEST_HOST_LOOP_INTERVAL        10UL
++#define TEST_HOST_LOOP_INTERVAL               10UL
 +
 +/*
 + * Guest/Host shared variables. Ensure addr_gva2hva() and/or
 + * sync_global_to/from_guest() are used when accessing from
 + * the host. READ/WRITE_ONCE() should also be used with anything
 + * that may change.
 + */
 +static uint64_t host_page_size;
 +static uint64_t guest_page_size;
 +static uint64_t guest_num_pages;
 +static uint64_t random_array[TEST_PAGES_PER_LOOP];
 +static uint64_t iteration;
  
  /*
 - * Guest variables.  We use these variables to share data between host
 - * and guest.  There are two copies of the variables, one in host memory
 - * (which is unused) and one in guest memory.  When the host wants to
 - * access these variables, it needs to call addr_gva2hva() to access the
 - * guest copy.
 + * GPA offset of the testing memory slot. Must be bigger than
 + * DEFAULT_GUEST_PHY_PAGES.
   */
 -uint64_t guest_random_array[TEST_PAGES_PER_LOOP];
 -uint64_t guest_iteration;
 -uint64_t guest_page_size;
 +static uint64_t guest_test_mem = DEFAULT_GUEST_TEST_MEM;
  
  /*
 - * Writes to the first byte of a random page within the testing memory
 - * region continuously.
 + * Continuously write to the first 8 bytes of a random pages within
 + * the testing memory region.
   */
 -void guest_code(void)
 +static void guest_code(void)
  {
 -      int i = 0;
 -      uint64_t volatile *array = guest_random_array;
 -      uint64_t volatile *guest_addr;
 +      int i;
  
        while (true) {
                for (i = 0; i < TEST_PAGES_PER_LOOP; i++) {
 -                      /*
 -                       * Write to the first 8 bytes of a random page
 -                       * on the testing memory region.
 -                       */
 -                      guest_addr = (uint64_t *)
 -                          (TEST_MEM_OFFSET +
 -                           (array[i] % TEST_MEM_PAGES) * guest_page_size);
 -                      *guest_addr = guest_iteration;
 +                      uint64_t addr = guest_test_mem;
 +                      addr += (READ_ONCE(random_array[i]) % guest_num_pages)
 +                              * guest_page_size;
 +                      addr &= ~(host_page_size - 1);
 +                      *(uint64_t *)addr = READ_ONCE(iteration);
                }
 +
                /* Tell the host that we need more random numbers */
                GUEST_SYNC(1);
        }
  }
  
 -/*
 - * Host variables.  These variables should only be used by the host
 - * rather than the guest.
 - */
 -bool host_quit;
 +/* Host variables */
 +static bool host_quit;
  
  /* Points to the test VM memory region on which we track dirty logs */
 -void *host_test_mem;
 +static void *host_test_mem;
 +static uint64_t host_num_pages;
  
  /* For statistics only */
 -uint64_t host_dirty_count;
 -uint64_t host_clear_count;
 -uint64_t host_track_next_count;
 +static uint64_t host_dirty_count;
 +static uint64_t host_clear_count;
 +static uint64_t host_track_next_count;
  
  /*
   * We use this bitmap to track some pages that should have its dirty
   * page bit is cleared in the latest bitmap, then the system must
   * report that write in the next get dirty log call.
   */
 -unsigned long *host_bmap_track;
 +static unsigned long *host_bmap_track;
  
 -void generate_random_array(uint64_t *guest_array, uint64_t size)
 +static void generate_random_array(uint64_t *guest_array, uint64_t size)
  {
        uint64_t i;
  
 -      for (i = 0; i < size; i++) {
 +      for (i = 0; i < size; i++)
                guest_array[i] = random();
 -      }
  }
  
 -void *vcpu_worker(void *data)
 +static void *vcpu_worker(void *data)
  {
        int ret;
 -      uint64_t loops, *guest_array, pages_count = 0;
        struct kvm_vm *vm = data;
 +      uint64_t *guest_array;
 +      uint64_t pages_count = 0;
        struct kvm_run *run;
 -      struct guest_args args;
 +      struct ucall uc;
  
        run = vcpu_state(vm, VCPU_ID);
  
 -      /* Retrieve the guest random array pointer and cache it */
 -      guest_array = addr_gva2hva(vm, (vm_vaddr_t)guest_random_array);
 -
 -      DEBUG("VCPU starts\n");
 -
 +      guest_array = addr_gva2hva(vm, (vm_vaddr_t)random_array);
        generate_random_array(guest_array, TEST_PAGES_PER_LOOP);
  
        while (!READ_ONCE(host_quit)) {
 -              /* Let the guest to dirty these random pages */
 +              /* Let the guest dirty the random pages */
                ret = _vcpu_run(vm, VCPU_ID);
 -              guest_args_read(vm, VCPU_ID, &args);
 -              if (run->exit_reason == KVM_EXIT_IO &&
 -                  args.port == GUEST_PORT_SYNC) {
 +              if (get_ucall(vm, VCPU_ID, &uc) == UCALL_SYNC) {
                        pages_count += TEST_PAGES_PER_LOOP;
                        generate_random_array(guest_array, TEST_PAGES_PER_LOOP);
                } else {
                }
        }
  
 -      DEBUG("VCPU exits, dirtied %"PRIu64" pages\n", pages_count);
 +      DEBUG("Dirtied %"PRIu64" pages\n", pages_count);
  
        return NULL;
  }
  
 -void vm_dirty_log_verify(unsigned long *bmap, uint64_t iteration)
 +static void vm_dirty_log_verify(unsigned long *bmap)
  {
        uint64_t page;
 -      uint64_t volatile *value_ptr;
 +      uint64_t *value_ptr;
 +      uint64_t step = host_page_size >= guest_page_size ? 1 :
 +                              guest_page_size / host_page_size;
  
 -      for (page = 0; page < TEST_MEM_PAGES; page++) {
 -              value_ptr = host_test_mem + page * getpagesize();
 +      for (page = 0; page < host_num_pages; page += step) {
 +              value_ptr = host_test_mem + page * host_page_size;
  
                /* If this is a special page that we were tracking... */
                if (test_and_clear_bit(page, host_bmap_track)) {
        }
  }
  
 -void help(char *name)
 +static struct kvm_vm *create_vm(enum vm_guest_mode mode, uint32_t vcpuid,
 +                              uint64_t extra_mem_pages, void *guest_code)
  {
 -      puts("");
 -      printf("usage: %s [-i iterations] [-I interval] [-h]\n", name);
 -      puts("");
 -      printf(" -i: specify iteration counts (default: %"PRIu64")\n",
 -             TEST_HOST_LOOP_N);
 -      printf(" -I: specify interval in ms (default: %"PRIu64" ms)\n",
 -             TEST_HOST_LOOP_INTERVAL);
 -      puts("");
 -      exit(0);
 +      struct kvm_vm *vm;
 +      uint64_t extra_pg_pages = extra_mem_pages / 512 * 2;
 +
 +      vm = vm_create(mode, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, O_RDWR);
 +      kvm_vm_elf_load(vm, program_invocation_name, 0, 0);
 +#ifdef __x86_64__
 +      vm_create_irqchip(vm);
 +#endif
 +      vm_vcpu_add_default(vm, vcpuid, guest_code);
 +      return vm;
  }
  
 -int main(int argc, char *argv[])
 +static void run_test(enum vm_guest_mode mode, unsigned long iterations,
 +                   unsigned long interval, bool top_offset)
  {
 +      unsigned int guest_pa_bits, guest_page_shift;
        pthread_t vcpu_thread;
        struct kvm_vm *vm;
 -      uint64_t volatile *psize, *iteration;
 -      unsigned long *bmap, iterations = TEST_HOST_LOOP_N,
 -          interval = TEST_HOST_LOOP_INTERVAL;
 -      int opt;
 -
 -      while ((opt = getopt(argc, argv, "hi:I:")) != -1) {
 -              switch (opt) {
 -              case 'i':
 -                      iterations = strtol(optarg, NULL, 10);
 -                      break;
 -              case 'I':
 -                      interval = strtol(optarg, NULL, 10);
 -                      break;
 -              case 'h':
 -              default:
 -                      help(argv[0]);
 -                      break;
 -              }
 +      uint64_t max_gfn;
 +      unsigned long *bmap;
 +
 +      switch (mode) {
 +      case VM_MODE_P52V48_4K:
 +              guest_pa_bits = 52;
 +              guest_page_shift = 12;
 +              break;
 +      case VM_MODE_P52V48_64K:
 +              guest_pa_bits = 52;
 +              guest_page_shift = 16;
 +              break;
 +      case VM_MODE_P40V48_4K:
 +              guest_pa_bits = 40;
 +              guest_page_shift = 12;
 +              break;
 +      case VM_MODE_P40V48_64K:
 +              guest_pa_bits = 40;
 +              guest_page_shift = 16;
 +              break;
 +      default:
 +              TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", mode);
        }
  
 -      TEST_ASSERT(iterations > 2, "Iteration must be bigger than zero\n");
 -      TEST_ASSERT(interval > 0, "Interval must be bigger than zero");
 +      DEBUG("Testing guest mode: %s\n", vm_guest_mode_string(mode));
  
 -      DEBUG("Test iterations: %"PRIu64", interval: %"PRIu64" (ms)\n",
 -            iterations, interval);
 +      max_gfn = (1ul << (guest_pa_bits - guest_page_shift)) - 1;
 +      guest_page_size = (1ul << guest_page_shift);
 +      /* 1G of guest page sized pages */
 +      guest_num_pages = (1ul << (30 - guest_page_shift));
 +      host_page_size = getpagesize();
 +      host_num_pages = (guest_num_pages * guest_page_size) / host_page_size +
 +                       !!((guest_num_pages * guest_page_size) % host_page_size);
  
 -      srandom(time(0));
 +      if (top_offset) {
 +              guest_test_mem = (max_gfn - guest_num_pages) * guest_page_size;
 +              guest_test_mem &= ~(host_page_size - 1);
 +      }
  
 -      bmap = bitmap_alloc(TEST_MEM_PAGES);
 -      host_bmap_track = bitmap_alloc(TEST_MEM_PAGES);
 +      DEBUG("guest test mem offset: 0x%lx\n", guest_test_mem);
  
 -      vm = vm_create_default(VCPU_ID, TEST_MEM_PAGES, guest_code);
 +      bmap = bitmap_alloc(host_num_pages);
 +      host_bmap_track = bitmap_alloc(host_num_pages);
 +
 +      vm = create_vm(mode, VCPU_ID, guest_num_pages, guest_code);
  
        /* Add an extra memory slot for testing dirty logging */
        vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
 -                                  TEST_MEM_OFFSET,
 +                                  guest_test_mem,
                                    TEST_MEM_SLOT_INDEX,
 -                                  TEST_MEM_PAGES,
 +                                  guest_num_pages,
                                    KVM_MEM_LOG_DIRTY_PAGES);
 -      /* Cache the HVA pointer of the region */
 -      host_test_mem = addr_gpa2hva(vm, (vm_paddr_t)TEST_MEM_OFFSET);
  
        /* Do 1:1 mapping for the dirty track memory slot */
 -      virt_map(vm, TEST_MEM_OFFSET, TEST_MEM_OFFSET,
 -               TEST_MEM_PAGES * getpagesize(), 0);
 +      virt_map(vm, guest_test_mem, guest_test_mem,
 +               guest_num_pages * guest_page_size, 0);
 +
 +      /* Cache the HVA pointer of the region */
 +      host_test_mem = addr_gpa2hva(vm, (vm_paddr_t)guest_test_mem);
  
 +#ifdef __x86_64__
        vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
 +#endif
 +#ifdef __aarch64__
 +      ucall_init(vm, UCALL_MMIO, NULL);
 +#endif
  
 -      /* Tell the guest about the page size on the system */
 -      psize = addr_gva2hva(vm, (vm_vaddr_t)&guest_page_size);
 -      *psize = getpagesize();
 +      /* Export the shared variables to the guest */
 +      sync_global_to_guest(vm, host_page_size);
 +      sync_global_to_guest(vm, guest_page_size);
 +      sync_global_to_guest(vm, guest_test_mem);
 +      sync_global_to_guest(vm, guest_num_pages);
  
        /* Start the iterations */
 -      iteration = addr_gva2hva(vm, (vm_vaddr_t)&guest_iteration);
 -      *iteration = 1;
 +      iteration = 1;
 +      sync_global_to_guest(vm, iteration);
 +      host_quit = false;
 +      host_dirty_count = 0;
 +      host_clear_count = 0;
 +      host_track_next_count = 0;
  
 -      /* Start dirtying pages */
        pthread_create(&vcpu_thread, NULL, vcpu_worker, vm);
  
 -      while (*iteration < iterations) {
 +      while (iteration < iterations) {
                /* Give the vcpu thread some time to dirty some pages */
                usleep(interval * 1000);
                kvm_vm_get_dirty_log(vm, TEST_MEM_SLOT_INDEX, bmap);
 -              vm_dirty_log_verify(bmap, *iteration);
 -              (*iteration)++;
 +              vm_dirty_log_verify(bmap);
 +              iteration++;
 +              sync_global_to_guest(vm, iteration);
        }
  
        /* Tell the vcpu thread to quit */
  
        free(bmap);
        free(host_bmap_track);
 +      ucall_uninit(vm);
        kvm_vm_free(vm);
 +}
 +
 +static struct vm_guest_modes {
 +      enum vm_guest_mode mode;
 +      bool supported;
 +      bool enabled;
 +} vm_guest_modes[NUM_VM_MODES] = {
 +#if defined(__x86_64__)
 +      { VM_MODE_P52V48_4K,    1, 1, },
 +      { VM_MODE_P52V48_64K,   0, 0, },
 +      { VM_MODE_P40V48_4K,    0, 0, },
 +      { VM_MODE_P40V48_64K,   0, 0, },
 +#elif defined(__aarch64__)
 +      { VM_MODE_P52V48_4K,    0, 0, },
 +      { VM_MODE_P52V48_64K,   0, 0, },
 +      { VM_MODE_P40V48_4K,    1, 1, },
 +      { VM_MODE_P40V48_64K,   1, 1, },
 +#endif
 +};
 +
 +static void help(char *name)
 +{
 +      int i;
 +
 +      puts("");
 +      printf("usage: %s [-h] [-i iterations] [-I interval] "
 +             "[-o offset] [-t] [-m mode]\n", name);
 +      puts("");
 +      printf(" -i: specify iteration counts (default: %"PRIu64")\n",
 +             TEST_HOST_LOOP_N);
 +      printf(" -I: specify interval in ms (default: %"PRIu64" ms)\n",
 +             TEST_HOST_LOOP_INTERVAL);
 +      printf(" -o: guest test memory offset (default: 0x%lx)\n",
 +             DEFAULT_GUEST_TEST_MEM);
 +      printf(" -t: map guest test memory at the top of the allowed "
 +             "physical address range\n");
 +      printf(" -m: specify the guest mode ID to test "
 +             "(default: test all supported modes)\n"
 +             "     This option may be used multiple times.\n"
 +             "     Guest mode IDs:\n");
 +      for (i = 0; i < NUM_VM_MODES; ++i) {
 +              printf("         %d:    %s%s\n",
 +                     vm_guest_modes[i].mode,
 +                     vm_guest_mode_string(vm_guest_modes[i].mode),
 +                     vm_guest_modes[i].supported ? " (supported)" : "");
 +      }
 +      puts("");
 +      exit(0);
 +}
 +
 +int main(int argc, char *argv[])
 +{
 +      unsigned long iterations = TEST_HOST_LOOP_N;
 +      unsigned long interval = TEST_HOST_LOOP_INTERVAL;
 +      bool mode_selected = false;
 +      bool top_offset = false;
 +      unsigned int mode;
 +      int opt, i;
 +
 +      while ((opt = getopt(argc, argv, "hi:I:o:tm:")) != -1) {
 +              switch (opt) {
 +              case 'i':
 +                      iterations = strtol(optarg, NULL, 10);
 +                      break;
 +              case 'I':
 +                      interval = strtol(optarg, NULL, 10);
 +                      break;
 +              case 'o':
 +                      guest_test_mem = strtoull(optarg, NULL, 0);
 +                      break;
 +              case 't':
 +                      top_offset = true;
 +                      break;
 +              case 'm':
 +                      if (!mode_selected) {
 +                              for (i = 0; i < NUM_VM_MODES; ++i)
 +                                      vm_guest_modes[i].enabled = 0;
 +                              mode_selected = true;
 +                      }
 +                      mode = strtoul(optarg, NULL, 10);
 +                      TEST_ASSERT(mode < NUM_VM_MODES,
 +                                  "Guest mode ID %d too big", mode);
 +                      vm_guest_modes[mode].enabled = 1;
 +                      break;
 +              case 'h':
 +              default:
 +                      help(argv[0]);
 +                      break;
 +              }
 +      }
 +
 +      TEST_ASSERT(iterations > 2, "Iterations must be greater than two");
 +      TEST_ASSERT(interval > 0, "Interval must be greater than zero");
 +      TEST_ASSERT(!top_offset || guest_test_mem == DEFAULT_GUEST_TEST_MEM,
 +                  "Cannot use both -o [offset] and -t at the same time");
 +
 +      DEBUG("Test iterations: %"PRIu64", interval: %"PRIu64" (ms)\n",
 +            iterations, interval);
 +
 +      srandom(time(0));
 +
 +      for (i = 0; i < NUM_VM_MODES; ++i) {
 +              if (!vm_guest_modes[i].enabled)
 +                      continue;
 +              TEST_ASSERT(vm_guest_modes[i].supported,
 +                          "Guest mode ID %d (%s) not supported.",
 +                          vm_guest_modes[i].mode,
 +                          vm_guest_mode_string(vm_guest_modes[i].mode));
 +              run_test(vm_guest_modes[i].mode, iterations, interval, top_offset);
 +      }
  
        return 0;
  }
index 8c06da4f03db302612feecdec516bd343af863e3,a56ef6b187bb73865840465eb439ed7325034520..1b41e71283d5b1d8afd6505f40943bfc35267a9b
  #include <sys/stat.h>
  #include <linux/kernel.h>
  
 -#define KVM_DEV_PATH "/dev/kvm"
 -
  #define KVM_UTIL_PGS_PER_HUGEPG 512
 -#define KVM_UTIL_MIN_PADDR      0x2000
 +#define KVM_UTIL_MIN_PFN      2
  
  /* Aligns x up to the next multiple of size. Size must be a power of 2. */
  static void *align(void *x, size_t size)
@@@ -28,8 -30,7 +28,8 @@@
        return (void *) (((size_t) x + mask) & ~mask);
  }
  
 -/* Capability
 +/*
 + * Capability
   *
   * Input Args:
   *   cap - Capability
@@@ -91,23 -92,16 +91,23 @@@ static void vm_open(struct kvm_vm *vm, 
        if (vm->kvm_fd < 0)
                exit(KSFT_SKIP);
  
 -      /* Create VM. */
        vm->fd = ioctl(vm->kvm_fd, KVM_CREATE_VM, NULL);
        TEST_ASSERT(vm->fd >= 0, "KVM_CREATE_VM ioctl failed, "
                "rc: %i errno: %i", vm->fd, errno);
  }
  
 -/* VM Create
 +const char * const vm_guest_mode_string[] = {
 +      "PA-bits:52, VA-bits:48, 4K pages",
 +      "PA-bits:52, VA-bits:48, 64K pages",
 +      "PA-bits:40, VA-bits:48, 4K pages",
 +      "PA-bits:40, VA-bits:48, 64K pages",
 +};
 +
 +/*
 + * VM Create
   *
   * Input Args:
 - *   mode - VM Mode (e.g. VM_MODE_FLAT48PG)
 + *   mode - VM Mode (e.g. VM_MODE_P52V48_4K)
   *   phy_pages - Physical memory pages
   *   perm - permission
   *
   * Return:
   *   Pointer to opaque structure that describes the created VM.
   *
 - * Creates a VM with the mode specified by mode (e.g. VM_MODE_FLAT48PG).
 + * Creates a VM with the mode specified by mode (e.g. VM_MODE_P52V48_4K).
   * When phy_pages is non-zero, a memory region of phy_pages physical pages
   * is created and mapped starting at guest physical address 0.  The file
   * descriptor to control the created VM is created with the permissions
@@@ -127,56 -121,35 +127,56 @@@ struct kvm_vm *vm_create(enum vm_guest_
        struct kvm_vm *vm;
        int kvm_fd;
  
 -      /* Allocate memory. */
        vm = calloc(1, sizeof(*vm));
-       TEST_ASSERT(vm != NULL, "Insufficent Memory");
+       TEST_ASSERT(vm != NULL, "Insufficient Memory");
  
        vm->mode = mode;
        vm_open(vm, perm);
  
        /* Setup mode specific traits. */
        switch (vm->mode) {
 -      case VM_MODE_FLAT48PG:
 +      case VM_MODE_P52V48_4K:
 +              vm->pgtable_levels = 4;
                vm->page_size = 0x1000;
                vm->page_shift = 12;
 -
 -              /* Limit to 48-bit canonical virtual addresses. */
 -              vm->vpages_valid = sparsebit_alloc();
 -              sparsebit_set_num(vm->vpages_valid,
 -                      0, (1ULL << (48 - 1)) >> vm->page_shift);
 -              sparsebit_set_num(vm->vpages_valid,
 -                      (~((1ULL << (48 - 1)) - 1)) >> vm->page_shift,
 -                      (1ULL << (48 - 1)) >> vm->page_shift);
 -
 -              /* Limit physical addresses to 52-bits. */
 -              vm->max_gfn = ((1ULL << 52) >> vm->page_shift) - 1;
 +              vm->va_bits = 48;
 +              break;
 +      case VM_MODE_P52V48_64K:
 +              vm->pgtable_levels = 3;
 +              vm->pa_bits = 52;
 +              vm->page_size = 0x10000;
 +              vm->page_shift = 16;
 +              vm->va_bits = 48;
 +              break;
 +      case VM_MODE_P40V48_4K:
 +              vm->pgtable_levels = 4;
 +              vm->pa_bits = 40;
 +              vm->va_bits = 48;
 +              vm->page_size = 0x1000;
 +              vm->page_shift = 12;
 +              break;
 +      case VM_MODE_P40V48_64K:
 +              vm->pgtable_levels = 3;
 +              vm->pa_bits = 40;
 +              vm->va_bits = 48;
 +              vm->page_size = 0x10000;
 +              vm->page_shift = 16;
                break;
 -
        default:
                TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", mode);
        }
  
 +      /* Limit to VA-bit canonical virtual addresses. */
 +      vm->vpages_valid = sparsebit_alloc();
 +      sparsebit_set_num(vm->vpages_valid,
 +              0, (1ULL << (vm->va_bits - 1)) >> vm->page_shift);
 +      sparsebit_set_num(vm->vpages_valid,
 +              (~((1ULL << (vm->va_bits - 1)) - 1)) >> vm->page_shift,
 +              (1ULL << (vm->va_bits - 1)) >> vm->page_shift);
 +
 +      /* Limit physical addresses to PA-bits. */
 +      vm->max_gfn = ((1ULL << vm->pa_bits) >> vm->page_shift) - 1;
 +
        /* Allocate and setup memory for guest. */
        vm->vpages_mapped = sparsebit_alloc();
        if (phy_pages != 0)
        return vm;
  }
  
 -/* VM Restart
 +/*
 + * VM Restart
   *
   * Input Args:
   *   vm - VM that has been released before
@@@ -214,8 -186,7 +214,8 @@@ void kvm_vm_restart(struct kvm_vm *vmp
                            "  rc: %i errno: %i\n"
                            "  slot: %u flags: 0x%x\n"
                            "  guest_phys_addr: 0x%lx size: 0x%lx",
 -                          ret, errno, region->region.slot, region->region.flags,
 +                          ret, errno, region->region.slot,
 +                          region->region.flags,
                            region->region.guest_phys_addr,
                            region->region.memory_size);
        }
@@@ -231,8 -202,7 +231,8 @@@ void kvm_vm_get_dirty_log(struct kvm_v
                    strerror(-ret));
  }
  
 -/* Userspace Memory Region Find
 +/*
 + * Userspace Memory Region Find
   *
   * Input Args:
   *   vm - Virtual Machine
   * of the regions is returned.  Null is returned only when no overlapping
   * region exists.
   */
 -static struct userspace_mem_region *userspace_mem_region_find(
 -      struct kvm_vm *vm, uint64_t start, uint64_t end)
 +static struct userspace_mem_region *
 +userspace_mem_region_find(struct kvm_vm *vm, uint64_t start, uint64_t end)
  {
        struct userspace_mem_region *region;
  
        return NULL;
  }
  
 -/* KVM Userspace Memory Region Find
 +/*
 + * KVM Userspace Memory Region Find
   *
   * Input Args:
   *   vm - Virtual Machine
@@@ -296,8 -265,7 +296,8 @@@ kvm_userspace_memory_region_find(struc
        return &region->region;
  }
  
 -/* VCPU Find
 +/*
 + * VCPU Find
   *
   * Input Args:
   *   vm - Virtual Machine
   * returns a pointer to it.  Returns NULL if the VM doesn't contain a VCPU
   * for the specified vcpuid.
   */
 -struct vcpu *vcpu_find(struct kvm_vm *vm,
 -      uint32_t vcpuid)
 +struct vcpu *vcpu_find(struct kvm_vm *vm, uint32_t vcpuid)
  {
        struct vcpu *vcpup;
  
        return NULL;
  }
  
 -/* VM VCPU Remove
 +/*
 + * VM VCPU Remove
   *
   * Input Args:
   *   vm - Virtual Machine
@@@ -362,9 -330,11 +362,9 @@@ void kvm_vm_release(struct kvm_vm *vmp
  {
        int ret;
  
 -      /* Free VCPUs. */
        while (vmp->vcpu_head)
                vm_vcpu_rm(vmp, vmp->vcpu_head->id);
  
 -      /* Close file descriptor for the VM. */
        ret = close(vmp->fd);
        TEST_ASSERT(ret == 0, "Close of vm fd failed,\n"
                "  vmp->fd: %i rc: %i errno: %i", vmp->fd, ret, errno);
                "  vmp->kvm_fd: %i rc: %i errno: %i", vmp->kvm_fd, ret, errno);
  }
  
 -/* Destroys and frees the VM pointed to by vmp.
 +/*
 + * Destroys and frees the VM pointed to by vmp.
   */
  void kvm_vm_free(struct kvm_vm *vmp)
  {
        free(vmp);
  }
  
 -/* Memory Compare, host virtual to guest virtual
 +/*
 + * Memory Compare, host virtual to guest virtual
   *
   * Input Args:
   *   hva - Starting host virtual address
   * a length of len, to the guest bytes starting at the guest virtual
   * address given by gva.
   */
 -int kvm_memcmp_hva_gva(void *hva,
 -      struct kvm_vm *vm, vm_vaddr_t gva, size_t len)
 +int kvm_memcmp_hva_gva(void *hva, struct kvm_vm *vm, vm_vaddr_t gva, size_t len)
  {
        size_t amt;
  
 -      /* Compare a batch of bytes until either a match is found
 +      /*
 +       * Compare a batch of bytes until either a match is found
         * or all the bytes have been compared.
         */
        for (uintptr_t offset = 0; offset < len; offset += amt) {
                uintptr_t ptr1 = (uintptr_t)hva + offset;
  
 -              /* Determine host address for guest virtual address
 +              /*
 +               * Determine host address for guest virtual address
                 * at offset.
                 */
                uintptr_t ptr2 = (uintptr_t)addr_gva2hva(vm, gva + offset);
  
 -              /* Determine amount to compare on this pass.
 +              /*
 +               * Determine amount to compare on this pass.
                 * Don't allow the comparsion to cross a page boundary.
                 */
                amt = len - offset;
                assert((ptr1 >> vm->page_shift) == ((ptr1 + amt - 1) >> vm->page_shift));
                assert((ptr2 >> vm->page_shift) == ((ptr2 + amt - 1) >> vm->page_shift));
  
 -              /* Perform the comparison.  If there is a difference
 +              /*
 +               * Perform the comparison.  If there is a difference
                 * return that result to the caller, otherwise need
                 * to continue on looking for a mismatch.
                 */
                        return ret;
        }
  
 -      /* No mismatch found.  Let the caller know the two memory
 +      /*
 +       * No mismatch found.  Let the caller know the two memory
         * areas are equal.
         */
        return 0;
  }
  
 -/* Allocate an instance of struct kvm_cpuid2
 - *
 - * Input Args: None
 - *
 - * Output Args: None
 - *
 - * Return: A pointer to the allocated struct. The caller is responsible
 - * for freeing this struct.
 - *
 - * Since kvm_cpuid2 uses a 0-length array to allow a the size of the
 - * array to be decided at allocation time, allocation is slightly
 - * complicated. This function uses a reasonable default length for
 - * the array and performs the appropriate allocation.
 - */
 -static struct kvm_cpuid2 *allocate_kvm_cpuid2(void)
 -{
 -      struct kvm_cpuid2 *cpuid;
 -      int nent = 100;
 -      size_t size;
 -
 -      size = sizeof(*cpuid);
 -      size += nent * sizeof(struct kvm_cpuid_entry2);
 -      cpuid = malloc(size);
 -      if (!cpuid) {
 -              perror("malloc");
 -              abort();
 -      }
 -
 -      cpuid->nent = nent;
 -
 -      return cpuid;
 -}
 -
 -/* KVM Supported CPUID Get
 - *
 - * Input Args: None
 - *
 - * Output Args:
 - *
 - * Return: The supported KVM CPUID
 - *
 - * Get the guest CPUID supported by KVM.
 - */
 -struct kvm_cpuid2 *kvm_get_supported_cpuid(void)
 -{
 -      static struct kvm_cpuid2 *cpuid;
 -      int ret;
 -      int kvm_fd;
 -
 -      if (cpuid)
 -              return cpuid;
 -
 -      cpuid = allocate_kvm_cpuid2();
 -      kvm_fd = open(KVM_DEV_PATH, O_RDONLY);
 -      if (kvm_fd < 0)
 -              exit(KSFT_SKIP);
 -
 -      ret = ioctl(kvm_fd, KVM_GET_SUPPORTED_CPUID, cpuid);
 -      TEST_ASSERT(ret == 0, "KVM_GET_SUPPORTED_CPUID failed %d %d\n",
 -                  ret, errno);
 -
 -      close(kvm_fd);
 -      return cpuid;
 -}
 -
 -/* Locate a cpuid entry.
 - *
 - * Input Args:
 - *   cpuid: The cpuid.
 - *   function: The function of the cpuid entry to find.
 - *
 - * Output Args: None
 - *
 - * Return: A pointer to the cpuid entry. Never returns NULL.
 - */
 -struct kvm_cpuid_entry2 *
 -kvm_get_supported_cpuid_index(uint32_t function, uint32_t index)
 -{
 -      struct kvm_cpuid2 *cpuid;
 -      struct kvm_cpuid_entry2 *entry = NULL;
 -      int i;
 -
 -      cpuid = kvm_get_supported_cpuid();
 -      for (i = 0; i < cpuid->nent; i++) {
 -              if (cpuid->entries[i].function == function &&
 -                  cpuid->entries[i].index == index) {
 -                      entry = &cpuid->entries[i];
 -                      break;
 -              }
 -      }
 -
 -      TEST_ASSERT(entry, "Guest CPUID entry not found: (EAX=%x, ECX=%x).",
 -                  function, index);
 -      return entry;
 -}
 -
 -/* VM Userspace Memory Region Add
 +/*
 + * VM Userspace Memory Region Add
   *
   * Input Args:
   *   vm - Virtual Machine
@@@ -527,8 -586,7 +527,8 @@@ void vm_userspace_mem_region_add(struc
                "  vm->max_gfn: 0x%lx vm->page_size: 0x%x",
                guest_paddr, npages, vm->max_gfn, vm->page_size);
  
 -      /* Confirm a mem region with an overlapping address doesn't
 +      /*
 +       * Confirm a mem region with an overlapping address doesn't
         * already exist.
         */
        region = (struct userspace_mem_region *) userspace_mem_region_find(
        vm->userspace_mem_region_head = region;
  }
  
 -/* Memslot to region
 +/*
 + * Memslot to region
   *
   * Input Args:
   *   vm - Virtual Machine
   *   on error (e.g. currently no memory region using memslot as a KVM
   *   memory slot ID).
   */
 -static struct userspace_mem_region *memslot2region(struct kvm_vm *vm,
 -      uint32_t memslot)
 +static struct userspace_mem_region *
 +memslot2region(struct kvm_vm *vm, uint32_t memslot)
  {
        struct userspace_mem_region *region;
  
        return region;
  }
  
 -/* VM Memory Region Flags Set
 +/*
 + * VM Memory Region Flags Set
   *
   * Input Args:
   *   vm - Virtual Machine
@@@ -674,6 -730,7 +674,6 @@@ void vm_mem_region_set_flags(struct kvm
        int ret;
        struct userspace_mem_region *region;
  
 -      /* Locate memory region. */
        region = memslot2region(vm, slot);
  
        region->region.flags = flags;
                ret, errno, slot, flags);
  }
  
 -/* VCPU mmap Size
 +/*
 + * VCPU mmap Size
   *
   * Input Args: None
   *
@@@ -716,8 -772,7 +716,8 @@@ static int vcpu_mmap_sz(void
        return ret;
  }
  
 -/* VM VCPU Add
 +/*
 + * VM VCPU Add
   *
   * Input Args:
   *   vm - Virtual Machine
   * Creates and adds to the VM specified by vm and virtual CPU with
   * the ID given by vcpuid.
   */
 -void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, int pgd_memslot, int gdt_memslot)
 +void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, int pgd_memslot,
 +               int gdt_memslot)
  {
        struct vcpu *vcpu;
  
        vcpu_setup(vm, vcpuid, pgd_memslot, gdt_memslot);
  }
  
 -/* VM Virtual Address Unused Gap
 +/*
 + * VM Virtual Address Unused Gap
   *
   * Input Args:
   *   vm - Virtual Machine
   * sz unallocated bytes >= vaddr_min is available.
   */
  static vm_vaddr_t vm_vaddr_unused_gap(struct kvm_vm *vm, size_t sz,
 -      vm_vaddr_t vaddr_min)
 +                                    vm_vaddr_t vaddr_min)
  {
        uint64_t pages = (sz + vm->page_size - 1) >> vm->page_shift;
  
        /* Determine lowest permitted virtual page index. */
        uint64_t pgidx_start = (vaddr_min + vm->page_size - 1) >> vm->page_shift;
        if ((pgidx_start * vm->page_size) < vaddr_min)
 -                      goto no_va_found;
 +              goto no_va_found;
  
        /* Loop over section with enough valid virtual page indexes. */
        if (!sparsebit_is_set_num(vm->vpages_valid,
@@@ -856,8 -909,7 +856,8 @@@ va_found
        return pgidx_start * vm->page_size;
  }
  
 -/* VM Virtual Address Allocate
 +/*
 + * VM Virtual Address Allocate
   *
   * Input Args:
   *   vm - Virtual Machine
   * a page.
   */
  vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min,
 -      uint32_t data_memslot, uint32_t pgd_memslot)
 +                        uint32_t data_memslot, uint32_t pgd_memslot)
  {
        uint64_t pages = (sz >> vm->page_shift) + ((sz % vm->page_size) != 0);
  
        virt_pgd_alloc(vm, pgd_memslot);
  
 -      /* Find an unused range of virtual page addresses of at least
 +      /*
 +       * Find an unused range of virtual page addresses of at least
         * pages in length.
         */
        vm_vaddr_t vaddr_start = vm_vaddr_unused_gap(vm, sz, vaddr_min);
                pages--, vaddr += vm->page_size) {
                vm_paddr_t paddr;
  
 -              paddr = vm_phy_page_alloc(vm, KVM_UTIL_MIN_PADDR, data_memslot);
 +              paddr = vm_phy_page_alloc(vm,
 +                              KVM_UTIL_MIN_PFN * vm->page_size, data_memslot);
  
                virt_pg_map(vm, vaddr, paddr, pgd_memslot);
  
@@@ -940,8 -990,7 +940,8 @@@ void virt_map(struct kvm_vm *vm, uint64
        }
  }
  
 -/* Address VM Physical to Host Virtual
 +/*
 + * Address VM Physical to Host Virtual
   *
   * Input Args:
   *   vm - Virtual Machine
@@@ -973,8 -1022,7 +973,8 @@@ void *addr_gpa2hva(struct kvm_vm *vm, v
        return NULL;
  }
  
 -/* Address Host Virtual to VM Physical
 +/*
 + * Address Host Virtual to VM Physical
   *
   * Input Args:
   *   vm - Virtual Machine
@@@ -1008,8 -1056,7 +1008,8 @@@ vm_paddr_t addr_hva2gpa(struct kvm_vm *
        return -1;
  }
  
 -/* VM Create IRQ Chip
 +/*
 + * VM Create IRQ Chip
   *
   * Input Args:
   *   vm - Virtual Machine
@@@ -1031,8 -1078,7 +1031,8 @@@ void vm_create_irqchip(struct kvm_vm *v
        vm->has_irqchip = true;
  }
  
 -/* VM VCPU State
 +/*
 + * VM VCPU State
   *
   * Input Args:
   *   vm - Virtual Machine
@@@ -1054,8 -1100,7 +1054,8 @@@ struct kvm_run *vcpu_state(struct kvm_v
        return vcpu->state;
  }
  
 -/* VM VCPU Run
 +/*
 + * VM VCPU Run
   *
   * Input Args:
   *   vm - Virtual Machine
@@@ -1081,14 -1126,13 +1081,14 @@@ int _vcpu_run(struct kvm_vm *vm, uint32
        int rc;
  
        TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid);
 -        do {
 +      do {
                rc = ioctl(vcpu->fd, KVM_RUN, NULL);
        } while (rc == -1 && errno == EINTR);
        return rc;
  }
  
 -/* VM VCPU Set MP State
 +/*
 + * VM VCPU Set MP State
   *
   * Input Args:
   *   vm - Virtual Machine
   * by mp_state.
   */
  void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid,
 -      struct kvm_mp_state *mp_state)
 +                     struct kvm_mp_state *mp_state)
  {
        struct vcpu *vcpu = vcpu_find(vm, vcpuid);
        int ret;
                "rc: %i errno: %i", ret, errno);
  }
  
 -/* VM VCPU Regs Get
 +/*
 + * VM VCPU Regs Get
   *
   * Input Args:
   *   vm - Virtual Machine
   * Obtains the current register state for the VCPU specified by vcpuid
   * and stores it at the location given by regs.
   */
 -void vcpu_regs_get(struct kvm_vm *vm,
 -      uint32_t vcpuid, struct kvm_regs *regs)
 +void vcpu_regs_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs)
  {
        struct vcpu *vcpu = vcpu_find(vm, vcpuid);
        int ret;
  
        TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid);
  
 -      /* Get the regs. */
        ret = ioctl(vcpu->fd, KVM_GET_REGS, regs);
        TEST_ASSERT(ret == 0, "KVM_GET_REGS failed, rc: %i errno: %i",
                ret, errno);
  }
  
 -/* VM VCPU Regs Set
 +/*
 + * VM VCPU Regs Set
   *
   * Input Args:
   *   vm - Virtual Machine
   * Sets the regs of the VCPU specified by vcpuid to the values
   * given by regs.
   */
 -void vcpu_regs_set(struct kvm_vm *vm,
 -      uint32_t vcpuid, struct kvm_regs *regs)
 +void vcpu_regs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs)
  {
        struct vcpu *vcpu = vcpu_find(vm, vcpuid);
        int ret;
  
        TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid);
  
 -      /* Set the regs. */
        ret = ioctl(vcpu->fd, KVM_SET_REGS, regs);
        TEST_ASSERT(ret == 0, "KVM_SET_REGS failed, rc: %i errno: %i",
                ret, errno);
  }
  
  void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid,
 -                        struct kvm_vcpu_events *events)
 +                   struct kvm_vcpu_events *events)
  {
        struct vcpu *vcpu = vcpu_find(vm, vcpuid);
        int ret;
  
        TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid);
  
 -      /* Get the regs. */
        ret = ioctl(vcpu->fd, KVM_GET_VCPU_EVENTS, events);
        TEST_ASSERT(ret == 0, "KVM_GET_VCPU_EVENTS, failed, rc: %i errno: %i",
                ret, errno);
  }
  
  void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid,
 -                        struct kvm_vcpu_events *events)
 +                   struct kvm_vcpu_events *events)
  {
        struct vcpu *vcpu = vcpu_find(vm, vcpuid);
        int ret;
  
        TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid);
  
 -      /* Set the regs. */
        ret = ioctl(vcpu->fd, KVM_SET_VCPU_EVENTS, events);
        TEST_ASSERT(ret == 0, "KVM_SET_VCPU_EVENTS, failed, rc: %i errno: %i",
                ret, errno);
  }
  
 -/* VCPU Get MSR
 - *
 - * Input Args:
 - *   vm - Virtual Machine
 - *   vcpuid - VCPU ID
 - *   msr_index - Index of MSR
 - *
 - * Output Args: None
 - *
 - * Return: On success, value of the MSR. On failure a TEST_ASSERT is produced.
 - *
 - * Get value of MSR for VCPU.
 - */
 -uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index)
 -{
 -      struct vcpu *vcpu = vcpu_find(vm, vcpuid);
 -      struct {
 -              struct kvm_msrs header;
 -              struct kvm_msr_entry entry;
 -      } buffer = {};
 -      int r;
 -
 -      TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid);
 -      buffer.header.nmsrs = 1;
 -      buffer.entry.index = msr_index;
 -      r = ioctl(vcpu->fd, KVM_GET_MSRS, &buffer.header);
 -      TEST_ASSERT(r == 1, "KVM_GET_MSRS IOCTL failed,\n"
 -              "  rc: %i errno: %i", r, errno);
 -
 -      return buffer.entry.data;
 -}
 -
 -/* VCPU Set MSR
 - *
 - * Input Args:
 - *   vm - Virtual Machine
 - *   vcpuid - VCPU ID
 - *   msr_index - Index of MSR
 - *   msr_value - New value of MSR
 - *
 - * Output Args: None
 - *
 - * Return: On success, nothing. On failure a TEST_ASSERT is produced.
 - *
 - * Set value of MSR for VCPU.
 - */
 -void vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index,
 -      uint64_t msr_value)
 -{
 -      struct vcpu *vcpu = vcpu_find(vm, vcpuid);
 -      struct {
 -              struct kvm_msrs header;
 -              struct kvm_msr_entry entry;
 -      } buffer = {};
 -      int r;
 -
 -      TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid);
 -      memset(&buffer, 0, sizeof(buffer));
 -      buffer.header.nmsrs = 1;
 -      buffer.entry.index = msr_index;
 -      buffer.entry.data = msr_value;
 -      r = ioctl(vcpu->fd, KVM_SET_MSRS, &buffer.header);
 -      TEST_ASSERT(r == 1, "KVM_SET_MSRS IOCTL failed,\n"
 -              "  rc: %i errno: %i", r, errno);
 -}
 -
 -/* VM VCPU Args Set
 - *
 - * Input Args:
 - *   vm - Virtual Machine
 - *   vcpuid - VCPU ID
 - *   num - number of arguments
 - *   ... - arguments, each of type uint64_t
 - *
 - * Output Args: None
 - *
 - * Return: None
 - *
 - * Sets the first num function input arguments to the values
 - * given as variable args.  Each of the variable args is expected to
 - * be of type uint64_t.
 - */
 -void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...)
 -{
 -      va_list ap;
 -      struct kvm_regs regs;
 -
 -      TEST_ASSERT(num >= 1 && num <= 6, "Unsupported number of args,\n"
 -                  "  num: %u\n",
 -                  num);
 -
 -      va_start(ap, num);
 -      vcpu_regs_get(vm, vcpuid, &regs);
 -
 -      if (num >= 1)
 -              regs.rdi = va_arg(ap, uint64_t);
 -
 -      if (num >= 2)
 -              regs.rsi = va_arg(ap, uint64_t);
 -
 -      if (num >= 3)
 -              regs.rdx = va_arg(ap, uint64_t);
 -
 -      if (num >= 4)
 -              regs.rcx = va_arg(ap, uint64_t);
 -
 -      if (num >= 5)
 -              regs.r8 = va_arg(ap, uint64_t);
 -
 -      if (num >= 6)
 -              regs.r9 = va_arg(ap, uint64_t);
 -
 -      vcpu_regs_set(vm, vcpuid, &regs);
 -      va_end(ap);
 -}
 -
 -/* VM VCPU System Regs Get
 +/*
 + * VM VCPU System Regs Get
   *
   * Input Args:
   *   vm - Virtual Machine
   * Obtains the current system register state for the VCPU specified by
   * vcpuid and stores it at the location given by sregs.
   */
 -void vcpu_sregs_get(struct kvm_vm *vm,
 -      uint32_t vcpuid, struct kvm_sregs *sregs)
 +void vcpu_sregs_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_sregs *sregs)
  {
        struct vcpu *vcpu = vcpu_find(vm, vcpuid);
        int ret;
  
        TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid);
  
 -      /* Get the regs. */
 -      /* Get the regs. */
        ret = ioctl(vcpu->fd, KVM_GET_SREGS, sregs);
        TEST_ASSERT(ret == 0, "KVM_GET_SREGS failed, rc: %i errno: %i",
                ret, errno);
  }
  
 -/* VM VCPU System Regs Set
 +/*
 + * VM VCPU System Regs Set
   *
   * Input Args:
   *   vm - Virtual Machine
   * Sets the system regs of the VCPU specified by vcpuid to the values
   * given by sregs.
   */
 -void vcpu_sregs_set(struct kvm_vm *vm,
 -      uint32_t vcpuid, struct kvm_sregs *sregs)
 +void vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_sregs *sregs)
  {
        int ret = _vcpu_sregs_set(vm, vcpuid, sregs);
        TEST_ASSERT(ret == 0, "KVM_RUN IOCTL failed, "
                "rc: %i errno: %i", ret, errno);
  }
  
 -int _vcpu_sregs_set(struct kvm_vm *vm,
 -      uint32_t vcpuid, struct kvm_sregs *sregs)
 +int _vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_sregs *sregs)
  {
        struct vcpu *vcpu = vcpu_find(vm, vcpuid);
        int ret;
  
        TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid);
  
 -      /* Get the regs. */
        return ioctl(vcpu->fd, KVM_SET_SREGS, sregs);
  }
  
 -/* VCPU Ioctl
 +/*
 + * VCPU Ioctl
   *
   * Input Args:
   *   vm - Virtual Machine
   *
   * Issues an arbitrary ioctl on a VCPU fd.
   */
 -void vcpu_ioctl(struct kvm_vm *vm,
 -      uint32_t vcpuid, unsigned long cmd, void *arg)
 +void vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid,
 +              unsigned long cmd, void *arg)
  {
        struct vcpu *vcpu = vcpu_find(vm, vcpuid);
        int ret;
                cmd, ret, errno, strerror(errno));
  }
  
 -/* VM Ioctl
 +/*
 + * VM Ioctl
   *
   * Input Args:
   *   vm - Virtual Machine
@@@ -1301,8 -1467,7 +1301,8 @@@ void vm_ioctl(struct kvm_vm *vm, unsign
                cmd, ret, errno, strerror(errno));
  }
  
 -/* VM Dump
 +/*
 + * VM Dump
   *
   * Input Args:
   *   vm - Virtual Machine
@@@ -1349,6 -1514,38 +1349,6 @@@ void vm_dump(FILE *stream, struct kvm_v
                vcpu_dump(stream, vm, vcpu->id, indent + 2);
  }
  
 -/* VM VCPU Dump
 - *
 - * Input Args:
 - *   vm - Virtual Machine
 - *   vcpuid - VCPU ID
 - *   indent - Left margin indent amount
 - *
 - * Output Args:
 - *   stream - Output FILE stream
 - *
 - * Return: None
 - *
 - * Dumps the current state of the VCPU specified by vcpuid, within the VM
 - * given by vm, to the FILE stream given by stream.
 - */
 -void vcpu_dump(FILE *stream, struct kvm_vm *vm,
 -      uint32_t vcpuid, uint8_t indent)
 -{
 -              struct kvm_regs regs;
 -              struct kvm_sregs sregs;
 -
 -              fprintf(stream, "%*scpuid: %u\n", indent, "", vcpuid);
 -
 -              fprintf(stream, "%*sregs:\n", indent + 2, "");
 -              vcpu_regs_get(vm, vcpuid, &regs);
 -              regs_dump(stream, &regs, indent + 4);
 -
 -              fprintf(stream, "%*ssregs:\n", indent + 2, "");
 -              vcpu_sregs_get(vm, vcpuid, &sregs);
 -              sregs_dump(stream, &sregs, indent + 4);
 -}
 -
  /* Known KVM exit reasons */
  static struct exit_reason {
        unsigned int reason;
  #endif
  };
  
 -/* Exit Reason String
 +/*
 + * Exit Reason String
   *
   * Input Args:
   *   exit_reason - Exit reason
@@@ -1406,12 -1602,10 +1406,12 @@@ const char *exit_reason_str(unsigned in
        return "Unknown";
  }
  
 -/* Physical Page Allocate
 +/*
 + * Physical Contiguous Page Allocator
   *
   * Input Args:
   *   vm - Virtual Machine
 + *   num - number of pages
   *   paddr_min - Physical address minimum
   *   memslot - Memory region to allocate page from
   *
   * Return:
   *   Starting physical address
   *
 - * Within the VM specified by vm, locates an available physical page
 - * at or above paddr_min.  If found, the page is marked as in use
 - * and its address is returned.  A TEST_ASSERT failure occurs if no
 - * page is available at or above paddr_min.
 + * Within the VM specified by vm, locates a range of available physical
 + * pages at or above paddr_min. If found, the pages are marked as in use
 + * and thier base address is returned. A TEST_ASSERT failure occurs if
 + * not enough pages are available at or above paddr_min.
   */
 -vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm,
 -      vm_paddr_t paddr_min, uint32_t memslot)
 +vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
 +                            vm_paddr_t paddr_min, uint32_t memslot)
  {
        struct userspace_mem_region *region;
 -      sparsebit_idx_t pg;
 +      sparsebit_idx_t pg, base;
 +
 +      TEST_ASSERT(num > 0, "Must allocate at least one page");
  
        TEST_ASSERT((paddr_min % vm->page_size) == 0, "Min physical address "
                "not divisible by page size.\n"
                "  paddr_min: 0x%lx page_size: 0x%x",
                paddr_min, vm->page_size);
  
 -      /* Locate memory region. */
        region = memslot2region(vm, memslot);
 +      base = pg = paddr_min >> vm->page_shift;
  
 -      /* Locate next available physical page at or above paddr_min. */
 -      pg = paddr_min >> vm->page_shift;
 -
 -      if (!sparsebit_is_set(region->unused_phy_pages, pg)) {
 -              pg = sparsebit_next_set(region->unused_phy_pages, pg);
 -              if (pg == 0) {
 -                      fprintf(stderr, "No guest physical page available, "
 -                              "paddr_min: 0x%lx page_size: 0x%x memslot: %u",
 -                              paddr_min, vm->page_size, memslot);
 -                      fputs("---- vm dump ----\n", stderr);
 -                      vm_dump(stderr, vm, 2);
 -                      abort();
 +      do {
 +              for (; pg < base + num; ++pg) {
 +                      if (!sparsebit_is_set(region->unused_phy_pages, pg)) {
 +                              base = pg = sparsebit_next_set(region->unused_phy_pages, pg);
 +                              break;
 +                      }
                }
 +      } while (pg && pg != base + num);
 +
 +      if (pg == 0) {
 +              fprintf(stderr, "No guest physical page available, "
 +                      "paddr_min: 0x%lx page_size: 0x%x memslot: %u\n",
 +                      paddr_min, vm->page_size, memslot);
 +              fputs("---- vm dump ----\n", stderr);
 +              vm_dump(stderr, vm, 2);
 +              abort();
        }
  
 -      /* Specify page as in use and return its address. */
 -      sparsebit_clear(region->unused_phy_pages, pg);
 +      for (pg = base; pg < base + num; ++pg)
 +              sparsebit_clear(region->unused_phy_pages, pg);
 +
 +      return base * vm->page_size;
 +}
  
 -      return pg * vm->page_size;
 +vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, vm_paddr_t paddr_min,
 +                           uint32_t memslot)
 +{
 +      return vm_phy_pages_alloc(vm, 1, paddr_min, memslot);
  }
  
 -/* Address Guest Virtual to Host Virtual
 +/*
 + * Address Guest Virtual to Host Virtual
   *
   * Input Args:
   *   vm - Virtual Machine
@@@ -1487,3 -1669,17 +1487,3 @@@ void *addr_gva2hva(struct kvm_vm *vm, v
  {
        return addr_gpa2hva(vm, addr_gva2gpa(vm, gva));
  }
 -
 -void guest_args_read(struct kvm_vm *vm, uint32_t vcpu_id,
 -                   struct guest_args *args)
 -{
 -      struct kvm_run *run = vcpu_state(vm, vcpu_id);
 -      struct kvm_regs regs;
 -
 -      memset(&regs, 0, sizeof(regs));
 -      vcpu_regs_get(vm, vcpu_id, &regs);
 -
 -      args->port = run->io.port;
 -      args->arg0 = regs.rdi;
 -      args->arg1 = regs.rsi;
 -}