mirror of
https://github.com/copy/v86.git
synced 2025-12-31 04:23:15 +00:00
Update kvm-unit-test from upstream
This commit is contained in:
parent
cda9398da5
commit
1b6c1091ce
65 changed files with 3718 additions and 889 deletions
3
tests/kvm-unit-tests/.gitignore
vendored
3
tests/kvm-unit-tests/.gitignore
vendored
|
|
@ -17,3 +17,6 @@ cscope.*
|
|||
/build-head
|
||||
/logs/
|
||||
/logs.old/
|
||||
/api/api-sample
|
||||
/api/dirty-log
|
||||
/api/dirty-log-perf
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
Copyright (C) 2006 Qumranet.
|
||||
Copyright (C) 2007-2017 by various contributors (see source files for details)
|
||||
|
||||
The files in this directory and its subdirectories are licensed under the
|
||||
GNU LGPL, version 2.
|
||||
The kvm-unit-tests are free software; the whole package can be redistributed
|
||||
and/or modified under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
Many files in this directory and its subdirectories are also licensed under
|
||||
the less restrictive GNU LGPL, version 2, or other compatible licenses. See
|
||||
the individual files for details.
|
||||
|
|
|
|||
|
|
@ -76,6 +76,13 @@ F: powerpc/*
|
|||
F: lib/powerpc/*
|
||||
F: lib/ppc64/*
|
||||
|
||||
S390X
|
||||
M: Thomas Huth <thuth@redhat.com>
|
||||
M: David Hildenbrand <david@redhat.com>
|
||||
L: kvm@vger.kernel.org
|
||||
F: s390x/*
|
||||
F: lib/s390x/*
|
||||
|
||||
X86
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
M: Radim Krčmář <rkrcmar@redhat.com>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
SHELL := /bin/bash
|
||||
SHELL := /usr/bin/env bash
|
||||
|
||||
ifeq ($(wildcard config.mak),)
|
||||
$(error run ./configure first. See ./configure -h)
|
||||
|
|
@ -7,8 +7,12 @@ endif
|
|||
|
||||
include config.mak
|
||||
|
||||
# Set search path for all sources
|
||||
VPATH = $(SRCDIR)
|
||||
|
||||
libdirs-get = $(shell [ -d "lib/$(1)" ] && echo "lib/$(1) lib/$(1)/asm")
|
||||
ARCH_LIBDIRS := $(call libdirs-get,$(ARCH)) $(call libdirs-get,$(TEST_DIR))
|
||||
OBJDIRS := $(ARCH_LIBDIRS)
|
||||
|
||||
DESTDIR := $(PREFIX)/share/kvm-unit-tests/
|
||||
|
||||
|
|
@ -30,13 +34,15 @@ cflatobjs := \
|
|||
|
||||
# libfdt paths
|
||||
LIBFDT_objdir = lib/libfdt
|
||||
LIBFDT_srcdir = lib/libfdt
|
||||
LIBFDT_srcdir = $(SRCDIR)/lib/libfdt
|
||||
LIBFDT_archive = $(LIBFDT_objdir)/libfdt.a
|
||||
LIBFDT_include = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_INCLUDES))
|
||||
LIBFDT_version = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_VERSION))
|
||||
|
||||
#include architecure specific make rules
|
||||
include $(TEST_DIR)/Makefile
|
||||
OBJDIRS += $(LIBFDT_objdir)
|
||||
|
||||
#include architecture specific make rules
|
||||
include $(SRCDIR)/$(TEST_DIR)/Makefile
|
||||
|
||||
# cc-option
|
||||
# Usage: OP_CFLAGS+=$(call cc-option, -falign-functions=0, -malign-functions=0)
|
||||
|
|
@ -44,8 +50,10 @@ include $(TEST_DIR)/Makefile
|
|||
cc-option = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \
|
||||
> /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
|
||||
|
||||
CFLAGS += -g
|
||||
CFLAGS += $(autodepend-flags) -Wall -Werror
|
||||
COMMON_CFLAGS += -g $(autodepend-flags)
|
||||
COMMON_CFLAGS += -Wall -Wwrite-strings -Wclobbered -Wempty-body -Wuninitialized
|
||||
COMMON_CFLAGS += -Wignored-qualifiers -Wunused-but-set-parameter
|
||||
COMMON_CFLAGS += -Werror
|
||||
frame-pointer-flag=-f$(if $(KEEP_FRAME_POINTER),no-,)omit-frame-pointer
|
||||
fomit_frame_pointer := $(call cc-option, $(frame-pointer-flag), "")
|
||||
fnostack_protector := $(call cc-option, -fno-stack-protector, "")
|
||||
|
|
@ -53,34 +61,42 @@ fnostack_protector_all := $(call cc-option, -fno-stack-protector-all, "")
|
|||
wno_frame_address := $(call cc-option, -Wno-frame-address, "")
|
||||
fno_pic := $(call cc-option, -fno-pic, "")
|
||||
no_pie := $(call cc-option, -no-pie, "")
|
||||
CFLAGS += $(fomit_frame_pointer)
|
||||
CFLAGS += $(fno_stack_protector)
|
||||
CFLAGS += $(fno_stack_protector_all)
|
||||
CFLAGS += $(wno_frame_address)
|
||||
CFLAGS += $(if $(U32_LONG_FMT),-D__U32_LONG_FMT__,)
|
||||
CFLAGS += $(fno_pic) $(no_pie)
|
||||
COMMON_CFLAGS += $(fomit_frame_pointer)
|
||||
COMMON_CFLAGS += $(fno_stack_protector)
|
||||
COMMON_CFLAGS += $(fno_stack_protector_all)
|
||||
COMMON_CFLAGS += $(wno_frame_address)
|
||||
COMMON_CFLAGS += $(if $(U32_LONG_FMT),-D__U32_LONG_FMT__,)
|
||||
COMMON_CFLAGS += $(fno_pic) $(no_pie)
|
||||
|
||||
CXXFLAGS += $(CFLAGS)
|
||||
CFLAGS += $(COMMON_CFLAGS)
|
||||
CFLAGS += -Wmissing-parameter-type -Wold-style-declaration -Woverride-init
|
||||
|
||||
CXXFLAGS += $(COMMON_CFLAGS)
|
||||
|
||||
autodepend-flags = -MMD -MF $(dir $*).$(notdir $*).d
|
||||
|
||||
LDFLAGS += $(CFLAGS)
|
||||
LDFLAGS += -pthread -lrt
|
||||
|
||||
$(libcflat): $(cflatobjs)
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
include $(LIBFDT_srcdir)/Makefile.libfdt
|
||||
$(LIBFDT_archive): CFLAGS += -ffreestanding -I lib -I lib/libfdt -Wno-sign-compare
|
||||
$(LIBFDT_archive): CFLAGS += -ffreestanding -I $(SRCDIR)/lib -I $(SRCDIR)/lib/libfdt -Wno-sign-compare
|
||||
$(LIBFDT_archive): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
|
||||
# Build directory target
|
||||
.PHONY: directories
|
||||
directories:
|
||||
@mkdir -p $(OBJDIRS)
|
||||
|
||||
%.o: %.S
|
||||
$(CC) $(CFLAGS) -c -nostdlib -o $@ $<
|
||||
|
||||
-include */.*.d */*/.*.d
|
||||
|
||||
all: $(shell git rev-parse --verify --short=8 HEAD >build-head 2>/dev/null)
|
||||
all: directories $(shell cd $(SRCDIR) && git rev-parse --verify --short=8 HEAD >$(PWD)/build-head 2>/dev/null)
|
||||
|
||||
standalone: all
|
||||
@scripts/mkstandalone.sh
|
||||
|
|
|
|||
82
tests/kvm-unit-tests/configure
vendored
82
tests/kvm-unit-tests/configure
vendored
|
|
@ -1,17 +1,20 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
srcdir=$(cd "$(dirname "$0")"; pwd)
|
||||
prefix=/usr/local
|
||||
cc=gcc
|
||||
cxx=g++
|
||||
ld=ld
|
||||
objcopy=objcopy
|
||||
objdump=objdump
|
||||
ar=ar
|
||||
addr2line=addr2line
|
||||
arch=i386
|
||||
arch=`uname -m | sed -e 's/i.86/i386/;s/arm.*/arm/;s/ppc64.*/ppc64/'`
|
||||
host=$arch
|
||||
cross_prefix=
|
||||
endian=""
|
||||
pretty_print_stacks=yes
|
||||
environ_default=yes
|
||||
u32_long=
|
||||
|
||||
usage() {
|
||||
|
|
@ -23,11 +26,15 @@ usage() {
|
|||
--processor=PROCESSOR processor to compile for ($arch)
|
||||
--cross-prefix=PREFIX cross compiler prefix
|
||||
--cc=CC c compiler to use ($cc)
|
||||
--cxx=CXX c++ compiler to use ($cxx)
|
||||
--ld=LD ld linker to use ($ld)
|
||||
--prefix=PREFIX where to install things ($prefix)
|
||||
--endian=ENDIAN endianness to compile for (little or big, ppc64 only)
|
||||
--[enable|disable]-pretty-print-stacks
|
||||
enable or disable pretty stack printing (enabled by default)
|
||||
--[enable|disable]-default-environ
|
||||
enable or disable the generation of a default environ when
|
||||
no environ is provided by the user (enabled by default)
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
|
@ -58,6 +65,9 @@ while [[ "$1" = -* ]]; do
|
|||
--cc)
|
||||
cc="$arg"
|
||||
;;
|
||||
--cxx)
|
||||
cxx="$arg"
|
||||
;;
|
||||
--ld)
|
||||
ld="$arg"
|
||||
;;
|
||||
|
|
@ -67,6 +77,12 @@ while [[ "$1" = -* ]]; do
|
|||
--disable-pretty-print-stacks)
|
||||
pretty_print_stacks=no
|
||||
;;
|
||||
--enable-default-environ)
|
||||
environ_default=yes
|
||||
;;
|
||||
--disable-default-environ)
|
||||
environ_default=no
|
||||
;;
|
||||
--help)
|
||||
usage
|
||||
;;
|
||||
|
|
@ -102,12 +118,12 @@ elif [ "$arch" = "ppc64" ]; then
|
|||
else
|
||||
testdir=$arch
|
||||
fi
|
||||
if [ ! -d $testdir ]; then
|
||||
if [ ! -d "$srcdir/$testdir" ]; then
|
||||
echo "$testdir does not exist!"
|
||||
exit 1
|
||||
fi
|
||||
if [ -f $testdir/run ]; then
|
||||
ln -fs $testdir/run $testdir-run
|
||||
if [ -f "$srcdir/$testdir/run" ]; then
|
||||
ln -fs "$srcdir/$testdir/run" $testdir-run
|
||||
fi
|
||||
|
||||
# check if uint32_t needs a long format modifier
|
||||
|
|
@ -117,42 +133,56 @@ EOF
|
|||
u32_long=$($cross_prefix$cc -E lib-test.c | grep -v '^#' | grep -q long && echo yes)
|
||||
rm -f lib-test.c
|
||||
|
||||
# check for dependent 32 bit libraries
|
||||
if [ "$arch" != "arm" ]; then
|
||||
cat << EOF > lib_test.c
|
||||
#include <stdc++.h>
|
||||
#include <boost_thread-mt.h>
|
||||
#include <pthread.h>
|
||||
|
||||
int main ()
|
||||
{}
|
||||
EOF
|
||||
$cc -m32 -o /dev/null lib_test.c &> /dev/null
|
||||
exit=$?
|
||||
if [ $exit -eq 0 ]; then
|
||||
api=true
|
||||
# api/: check for dependent 32 bit libraries and gnu++11 support
|
||||
if [ "$testdir" = "x86" ]; then
|
||||
echo 'int main () {}' > lib-test.c
|
||||
$cc -m32 -o /dev/null -lstdc++ -lpthread -lrt lib-test.c &> /dev/null
|
||||
exit=$?
|
||||
$cxx -m32 -o /dev/null -std=gnu++11 lib-test.c &> /dev/null
|
||||
if [ $? -eq 0 -a $exit -eq 0 ]; then
|
||||
api=true
|
||||
fi
|
||||
rm -f lib-test.c
|
||||
fi
|
||||
rm -f lib_test.c
|
||||
|
||||
# Are we in a separate build tree? If so, link the Makefile
|
||||
# and shared stuff so that 'make' and run_tests.sh work.
|
||||
if test ! -e Makefile; then
|
||||
echo "linking Makefile..."
|
||||
ln -s "$srcdir/Makefile" .
|
||||
|
||||
echo "linking tests..."
|
||||
mkdir -p $testdir
|
||||
ln -sf "$srcdir/$testdir/run" $testdir/
|
||||
ln -sf "$srcdir/$testdir/unittests.cfg" $testdir/
|
||||
ln -sf "$srcdir/run_tests.sh"
|
||||
|
||||
echo "linking scripts..."
|
||||
ln -sf "$srcdir/scripts"
|
||||
fi
|
||||
|
||||
# link lib/asm for the architecture
|
||||
rm -f lib/asm
|
||||
asm=asm-generic
|
||||
if [ -d lib/$arch/asm ]; then
|
||||
asm=$arch/asm
|
||||
elif [ -d lib/$testdir/asm ]; then
|
||||
asm=$testdir/asm
|
||||
if [ -d "$srcdir/lib/$arch/asm" ]; then
|
||||
asm="$srcdir/lib/$arch/asm"
|
||||
elif [ -d "$srcdir/lib/$testdir/asm" ]; then
|
||||
asm="$srcdir/lib/$testdir/asm"
|
||||
fi
|
||||
ln -s $asm lib/asm
|
||||
mkdir -p lib
|
||||
ln -sf "$asm" lib/asm
|
||||
|
||||
|
||||
# create the config
|
||||
cat <<EOF > config.mak
|
||||
SRCDIR=$srcdir
|
||||
PREFIX=$prefix
|
||||
HOST=$host
|
||||
ARCH=$arch
|
||||
ARCH_NAME=$arch_name
|
||||
PROCESSOR=$processor
|
||||
CC=$cross_prefix$cc
|
||||
CXX=$cross_prefix$cxx
|
||||
LD=$cross_prefix$ld
|
||||
OBJCOPY=$cross_prefix$objcopy
|
||||
OBJDUMP=$cross_prefix$objdump
|
||||
|
|
@ -163,5 +193,7 @@ TEST_DIR=$testdir
|
|||
FIRMWARE=$firmware
|
||||
ENDIAN=$endian
|
||||
PRETTY_PRINT_STACKS=$pretty_print_stacks
|
||||
ENVIRON_DEFAULT=$environ_default
|
||||
ERRATATXT=errata.txt
|
||||
U32_LONG_FMT=$u32_long
|
||||
EOF
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ void phys_alloc_show(void)
|
|||
int i;
|
||||
|
||||
spin_lock(&lock);
|
||||
printf("phys_alloc minimum alignment: 0x%" PRIx64 "\n",
|
||||
printf("phys_alloc minimum alignment: %#" PRIx64 "\n",
|
||||
(u64)align_min);
|
||||
for (i = 0; i < nr_regions; ++i)
|
||||
printf("%016" PRIx64 "-%016" PRIx64 " [%s]\n",
|
||||
|
|
@ -75,10 +75,10 @@ static phys_addr_t phys_alloc_aligned_safe(phys_addr_t size,
|
|||
size += addr - base;
|
||||
|
||||
if ((top_safe - base) < size) {
|
||||
printf("phys_alloc: requested=0x%" PRIx64
|
||||
" (align=0x%" PRIx64 "), "
|
||||
"need=0x%" PRIx64 ", but free=0x%" PRIx64 ". "
|
||||
"top=0x%" PRIx64 ", top_safe=0x%" PRIx64 "\n",
|
||||
printf("phys_alloc: requested=%#" PRIx64
|
||||
" (align=%#" PRIx64 "), "
|
||||
"need=%#" PRIx64 ", but free=%#" PRIx64 ". "
|
||||
"top=%#" PRIx64 ", top_safe=%#" PRIx64 "\n",
|
||||
(u64)size_orig, (u64)align, (u64)size, top_safe - base,
|
||||
(u64)top, top_safe);
|
||||
spin_unlock(&lock);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,16 @@
|
|||
/*
|
||||
* Set up arguments for main() and prepare environment variables
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Library General Public License version 2.
|
||||
*/
|
||||
|
||||
#include "libcflat.h"
|
||||
#include "argv.h"
|
||||
#include "auxinfo.h"
|
||||
|
||||
int __argc;
|
||||
char *__args;
|
||||
const char *__args;
|
||||
char *__argv[100];
|
||||
char *__environ[200];
|
||||
|
||||
|
|
@ -15,7 +23,7 @@ static char *copy_ptr = args_copy;
|
|||
#define isalpha(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z') || (c) == '_')
|
||||
#define isalnum(c) (isalpha(c) || ((c) >= '0' && (c) <= '9'))
|
||||
|
||||
static char *skip_blanks(char *p)
|
||||
static const char *skip_blanks(const char *p)
|
||||
{
|
||||
while (isblank(*p))
|
||||
++p;
|
||||
|
|
@ -24,7 +32,7 @@ static char *skip_blanks(char *p)
|
|||
|
||||
void __setup_args(void)
|
||||
{
|
||||
char *args = __args;
|
||||
const char *args = __args;
|
||||
char **argv = __argv + __argc;
|
||||
|
||||
while (*(args = skip_blanks(args)) != '\0') {
|
||||
|
|
@ -36,7 +44,7 @@ void __setup_args(void)
|
|||
__argc = argv - __argv;
|
||||
}
|
||||
|
||||
void setup_args(char *args)
|
||||
static void setup_args(const char *args)
|
||||
{
|
||||
if (!args)
|
||||
return;
|
||||
|
|
@ -45,16 +53,13 @@ void setup_args(char *args)
|
|||
__setup_args();
|
||||
}
|
||||
|
||||
void setup_args_progname(char *args)
|
||||
void setup_args_progname(const char *args)
|
||||
{
|
||||
__argv[0] = copy_ptr;
|
||||
strcpy(__argv[0], auxinfo.progname);
|
||||
copy_ptr += strlen(auxinfo.progname) + 1;
|
||||
++__argc;
|
||||
if (args) {
|
||||
__args = args;
|
||||
__setup_args();
|
||||
}
|
||||
setup_args(args);
|
||||
}
|
||||
|
||||
static char *env_eol(char *env)
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
* adapted from the Linux kernel's include/asm-generic/io.h
|
||||
* and arch/arm/include/asm/io.h
|
||||
*
|
||||
* Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
|
||||
* Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.
|
||||
* This work is licensed under the terms of the GNU GPL, version 2.
|
||||
*/
|
||||
#include "libcflat.h"
|
||||
#include "asm/page.h"
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
* asm-generic/page.h
|
||||
* adapted from the Linux kernel's include/asm-generic/page.h
|
||||
*
|
||||
* Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
|
||||
* Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.
|
||||
* This work is licensed under the terms of the GNU GPL, version 2.
|
||||
*/
|
||||
|
||||
#include <linux/const.h>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,18 @@
|
|||
#ifndef _ASM_GENERIC_SPINLOCK_H_
|
||||
#define _ASM_GENERIC_SPINLOCK_H_
|
||||
#error need architecture specific asm/spinlock.h
|
||||
|
||||
struct spinlock {
|
||||
unsigned int v;
|
||||
};
|
||||
|
||||
static inline void spin_lock(struct spinlock *lock)
|
||||
{
|
||||
while (__sync_lock_test_and_set(&lock->v, 1));
|
||||
}
|
||||
|
||||
static inline void spin_unlock(struct spinlock *lock)
|
||||
{
|
||||
__sync_lock_release(&lock->v);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
/*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Library General Public License version 2.
|
||||
*/
|
||||
#ifndef _AUXINFO_H_
|
||||
#define _AUXINFO_H_
|
||||
struct auxinfo {
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@
|
|||
#define _BITOPS_H_
|
||||
|
||||
/*
|
||||
* Adapated from
|
||||
* Adapted from
|
||||
* include/linux/bitops.h
|
||||
*
|
||||
* Copyright (C) 2015, Red Hat Inc, Andrew Jones <drjones@redhat.com>
|
||||
* Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.
|
||||
* This work is licensed under the terms of the GNU GPL, version 2.
|
||||
*/
|
||||
|
||||
#define BITS_PER_LONG_LONG 64
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
/*
|
||||
* errata functions
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Library General Public License version 2.
|
||||
*/
|
||||
#ifndef _ERRATA_H_
|
||||
#define _ERRATA_H_
|
||||
|
||||
|
|
@ -7,16 +13,33 @@
|
|||
#define _ERRATA_RELAXED(erratum) errata_relaxed("ERRATA_" # erratum)
|
||||
#define ERRATA_RELAXED(erratum) _ERRATA_RELAXED(erratum)
|
||||
|
||||
static inline bool errata_force(void)
|
||||
{
|
||||
char *s = getenv("ERRATA_FORCE");
|
||||
|
||||
return s && (*s == '1' || *s == 'y' || *s == 'Y');
|
||||
}
|
||||
|
||||
static inline bool errata(const char *erratum)
|
||||
{
|
||||
char *s = getenv(erratum);
|
||||
char *s;
|
||||
|
||||
if (errata_force())
|
||||
return true;
|
||||
|
||||
s = getenv(erratum);
|
||||
|
||||
return s && (*s == '1' || *s == 'y' || *s == 'Y');
|
||||
}
|
||||
|
||||
static inline bool errata_relaxed(const char *erratum)
|
||||
{
|
||||
char *s = getenv(erratum);
|
||||
char *s;
|
||||
|
||||
if (errata_force())
|
||||
return true;
|
||||
|
||||
s = getenv(erratum);
|
||||
|
||||
return !(s && (*s == '0' || *s == 'n' || *s == 'N'));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,15 +96,25 @@ extern int vsnprintf(char *buf, int size, const char *fmt, va_list va)
|
|||
extern int vprintf(const char *fmt, va_list va)
|
||||
__attribute__((format(printf, 1, 0)));
|
||||
|
||||
void report_prefix_pushf(const char *prefix_fmt, ...)
|
||||
__attribute__((format(printf, 1, 2)));
|
||||
extern void report_prefix_push(const char *prefix);
|
||||
extern void report_prefix_pop(void);
|
||||
extern void report(const char *msg_fmt, bool pass, ...);
|
||||
extern void report_xfail(const char *msg_fmt, bool xfail, bool pass, ...);
|
||||
extern void report_abort(const char *msg_fmt, ...);
|
||||
extern void report_skip(const char *msg_fmt, ...);
|
||||
extern void report_info(const char *msg_fmt, ...);
|
||||
extern void report(const char *msg_fmt, bool pass, ...)
|
||||
__attribute__((format(printf, 1, 3)));
|
||||
extern void report_xfail(const char *msg_fmt, bool xfail, bool pass, ...)
|
||||
__attribute__((format(printf, 1, 4)));
|
||||
extern void report_abort(const char *msg_fmt, ...)
|
||||
__attribute__((format(printf, 1, 2)));
|
||||
extern void report_skip(const char *msg_fmt, ...)
|
||||
__attribute__((format(printf, 1, 2)));
|
||||
extern void report_info(const char *msg_fmt, ...)
|
||||
__attribute__((format(printf, 1, 2)));
|
||||
extern void report_pass(void);
|
||||
extern int report_summary(void);
|
||||
|
||||
bool simple_glob(const char *text, const char *pattern);
|
||||
|
||||
extern void dump_stack(void);
|
||||
extern void dump_frame_stack(const void *instruction, const void *frame);
|
||||
|
||||
|
|
@ -124,9 +134,26 @@ do { \
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
#define assert_msg(cond, fmt, args...) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
printf("%s:%d: assert failed: %s: " fmt "\n", \
|
||||
__FILE__, __LINE__, #cond, ## args); \
|
||||
dump_stack(); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static inline bool is_power_of_2(unsigned long n)
|
||||
{
|
||||
return n && !(n & (n - 1));
|
||||
}
|
||||
|
||||
/*
|
||||
* One byte per bit, a ' between each group of 4 bits, and a null terminator.
|
||||
*/
|
||||
#define BINSTR_SZ (sizeof(unsigned long) * 8 + sizeof(unsigned long) * 2)
|
||||
void binstr(unsigned long x, char out[BINSTR_SZ]);
|
||||
void print_binstr(unsigned long x);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ void edu_dma(struct pci_edu_dev *dev, iova_t iova,
|
|||
assert(size <= EDU_DMA_SIZE_MAX);
|
||||
assert(dev_offset < EDU_DMA_SIZE_MAX);
|
||||
|
||||
printf("edu device DMA start %s addr 0x%" PRIx64 " size 0x%lu off 0x%x\n",
|
||||
printf("edu device DMA start %s addr %#" PRIx64 " size %lu off %#x\n",
|
||||
from_device ? "FROM" : "TO",
|
||||
iova, (ulong)size, dev_offset);
|
||||
|
||||
|
|
|
|||
|
|
@ -131,8 +131,8 @@ static bool pci_testdev_one(struct pci_test_dev_hdr *test,
|
|||
return (int)count == nr_writes;
|
||||
}
|
||||
|
||||
void pci_testdev_print(struct pci_test_dev_hdr *test,
|
||||
struct pci_testdev_ops *ops)
|
||||
static void pci_testdev_print(struct pci_test_dev_hdr *test,
|
||||
struct pci_testdev_ops *ops)
|
||||
{
|
||||
bool io = (ops == &pci_testdev_io_ops);
|
||||
int i;
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ bool pci_setup_msi(struct pci_dev *dev, uint64_t msi_addr, uint32_t msi_data)
|
|||
assert(dev);
|
||||
|
||||
if (!dev->msi_offset) {
|
||||
printf("MSI: dev 0x%x does not support MSI.\n", dev->bdf);
|
||||
printf("MSI: dev %#x does not support MSI.\n", dev->bdf);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -112,6 +112,8 @@ uint32_t pci_bar_mask(uint32_t bar)
|
|||
|
||||
uint32_t pci_bar_get(struct pci_dev *dev, int bar_num)
|
||||
{
|
||||
ASSERT_BAR_NUM(bar_num);
|
||||
|
||||
return pci_config_readl(dev->bdf, PCI_BASE_ADDRESS_0 +
|
||||
bar_num * 4);
|
||||
}
|
||||
|
|
@ -134,6 +136,8 @@ static phys_addr_t __pci_bar_get_addr(struct pci_dev *dev, int bar_num)
|
|||
|
||||
phys_addr_t pci_bar_get_addr(struct pci_dev *dev, int bar_num)
|
||||
{
|
||||
ASSERT_BAR_NUM(bar_num);
|
||||
|
||||
return dev->resource[bar_num];
|
||||
}
|
||||
|
||||
|
|
@ -141,11 +145,19 @@ void pci_bar_set_addr(struct pci_dev *dev, int bar_num, phys_addr_t addr)
|
|||
{
|
||||
int off = PCI_BASE_ADDRESS_0 + bar_num * 4;
|
||||
|
||||
assert(addr != INVALID_PHYS_ADDR);
|
||||
assert(dev->resource[bar_num] != INVALID_PHYS_ADDR);
|
||||
|
||||
ASSERT_BAR_NUM(bar_num);
|
||||
if (pci_bar_is64(dev, bar_num))
|
||||
ASSERT_BAR_NUM(bar_num + 1);
|
||||
else
|
||||
assert((addr >> 32) == 0);
|
||||
|
||||
pci_config_writel(dev->bdf, off, (uint32_t)addr);
|
||||
dev->resource[bar_num] = addr;
|
||||
|
||||
if (pci_bar_is64(dev, bar_num)) {
|
||||
assert(bar_num + 1 < PCI_BAR_NUM);
|
||||
pci_config_writel(dev->bdf, off + 4, (uint32_t)(addr >> 32));
|
||||
dev->resource[bar_num + 1] = dev->resource[bar_num];
|
||||
}
|
||||
|
|
@ -283,10 +295,10 @@ static void pci_cap_print(struct pci_dev *dev, int cap_offset, int cap_id)
|
|||
break;
|
||||
}
|
||||
default:
|
||||
printf("\tcapability 0x%02x ", cap_id);
|
||||
printf("\tcapability %#04x ", cap_id);
|
||||
break;
|
||||
}
|
||||
printf("at offset 0x%02x\n", cap_offset);
|
||||
printf("at offset %#04x\n", cap_offset);
|
||||
}
|
||||
|
||||
void pci_dev_print(struct pci_dev *dev)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ enum {
|
|||
#define PCI_BAR_NUM 6
|
||||
#define PCI_DEVFN_MAX 256
|
||||
|
||||
#define ASSERT_BAR_NUM(bar_num) \
|
||||
do { assert(bar_num >= 0 && bar_num < PCI_BAR_NUM); } while (0)
|
||||
|
||||
#define PCI_BDF_GET_DEVFN(x) ((x) & 0xff)
|
||||
#define PCI_BDF_GET_BUS(x) (((x) >> 8) & 0xff)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
/*
|
||||
* libc printf and friends
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Library General Public License version 2.
|
||||
*/
|
||||
|
||||
#include "libcflat.h"
|
||||
|
||||
#define BUFSZ 2000
|
||||
|
|
@ -11,6 +18,7 @@ typedef struct pstream {
|
|||
typedef struct strprops {
|
||||
char pad;
|
||||
int npad;
|
||||
bool alternate;
|
||||
} strprops_t;
|
||||
|
||||
static void addchar(pstream_t *p, char c)
|
||||
|
|
@ -22,7 +30,7 @@ static void addchar(pstream_t *p, char c)
|
|||
++p->added;
|
||||
}
|
||||
|
||||
void print_str(pstream_t *p, const char *s, strprops_t props)
|
||||
static void print_str(pstream_t *p, const char *s, strprops_t props)
|
||||
{
|
||||
const char *s_orig = s;
|
||||
int npad = props.npad;
|
||||
|
|
@ -50,7 +58,7 @@ void print_str(pstream_t *p, const char *s, strprops_t props)
|
|||
|
||||
static char digits[16] = "0123456789abcdef";
|
||||
|
||||
void print_int(pstream_t *ps, long long n, int base, strprops_t props)
|
||||
static void print_int(pstream_t *ps, long long n, int base, strprops_t props)
|
||||
{
|
||||
char buf[sizeof(long) * 3 + 2], *p = buf;
|
||||
int s = 0, i;
|
||||
|
|
@ -84,10 +92,10 @@ void print_int(pstream_t *ps, long long n, int base, strprops_t props)
|
|||
print_str(ps, buf, props);
|
||||
}
|
||||
|
||||
void print_unsigned(pstream_t *ps, unsigned long long n, int base,
|
||||
strprops_t props)
|
||||
static void print_unsigned(pstream_t *ps, unsigned long long n, int base,
|
||||
strprops_t props)
|
||||
{
|
||||
char buf[sizeof(long) * 3 + 1], *p = buf;
|
||||
char buf[sizeof(long) * 3 + 3], *p = buf;
|
||||
int i;
|
||||
|
||||
while (n) {
|
||||
|
|
@ -97,6 +105,18 @@ void print_unsigned(pstream_t *ps, unsigned long long n, int base,
|
|||
|
||||
if (p == buf)
|
||||
*p++ = '0';
|
||||
else if (props.alternate && base == 16) {
|
||||
if (props.pad == '0') {
|
||||
addchar(ps, '0');
|
||||
addchar(ps, 'x');
|
||||
|
||||
if (props.npad > 0)
|
||||
props.npad = MAX(props.npad - 2, 0);
|
||||
} else {
|
||||
*p++ = 'x';
|
||||
*p++ = '0';
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < (p - buf) / 2; ++i) {
|
||||
char tmp;
|
||||
|
|
@ -157,6 +177,9 @@ int vsnprintf(char *buf, int size, const char *fmt, va_list va)
|
|||
case '\0':
|
||||
--fmt;
|
||||
break;
|
||||
case '#':
|
||||
props.alternate = true;
|
||||
goto morefmt;
|
||||
case '0':
|
||||
props.pad = '0';
|
||||
++fmt;
|
||||
|
|
@ -169,6 +192,15 @@ int vsnprintf(char *buf, int size, const char *fmt, va_list va)
|
|||
case 'l':
|
||||
++nlong;
|
||||
goto morefmt;
|
||||
case 't':
|
||||
case 'z':
|
||||
/* Here we only care that sizeof(size_t) == sizeof(long).
|
||||
* On a 32-bit platform it doesn't matter that size_t is
|
||||
* typedef'ed to int or long; va_arg will work either way.
|
||||
* Same for ptrdiff_t (%td).
|
||||
*/
|
||||
nlong = 1;
|
||||
goto morefmt;
|
||||
case 'd':
|
||||
switch (nlong) {
|
||||
case 0:
|
||||
|
|
@ -209,7 +241,7 @@ int vsnprintf(char *buf, int size, const char *fmt, va_list va)
|
|||
}
|
||||
break;
|
||||
case 'p':
|
||||
print_str(&s, "0x", props);
|
||||
props.alternate = true;
|
||||
print_unsigned(&s, (unsigned long)va_arg(va, void *), 16, props);
|
||||
break;
|
||||
case 's':
|
||||
|
|
@ -221,7 +253,6 @@ int vsnprintf(char *buf, int size, const char *fmt, va_list va)
|
|||
}
|
||||
}
|
||||
*s.buffer = 0;
|
||||
++s.added;
|
||||
return s.added;
|
||||
}
|
||||
|
||||
|
|
@ -259,3 +290,33 @@ int printf(const char *fmt, ...)
|
|||
puts(buf);
|
||||
return r;
|
||||
}
|
||||
|
||||
void binstr(unsigned long x, char out[BINSTR_SZ])
|
||||
{
|
||||
int i;
|
||||
char *c;
|
||||
int n;
|
||||
|
||||
n = sizeof(unsigned long) * 8;
|
||||
i = 0;
|
||||
c = &out[0];
|
||||
for (;;) {
|
||||
*c++ = (x & (1ul << (n - i - 1))) ? '1' : '0';
|
||||
i++;
|
||||
|
||||
if (i == n) {
|
||||
*c = '\0';
|
||||
break;
|
||||
}
|
||||
if (i % 4 == 0)
|
||||
*c++ = '\'';
|
||||
}
|
||||
assert(c + 1 - &out[0] == BINSTR_SZ);
|
||||
}
|
||||
|
||||
void print_binstr(unsigned long x)
|
||||
{
|
||||
char out[BINSTR_SZ];
|
||||
binstr(x, out);
|
||||
printf("%s", out);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,14 +17,49 @@ static unsigned int tests, failures, xfailures, skipped;
|
|||
static char prefixes[256];
|
||||
static struct spinlock lock;
|
||||
|
||||
void report_prefix_push(const char *prefix)
|
||||
#define PREFIX_DELIMITER ": "
|
||||
|
||||
void report_pass(void)
|
||||
{
|
||||
spin_lock(&lock);
|
||||
strcat(prefixes, prefix);
|
||||
strcat(prefixes, ": ");
|
||||
tests++;
|
||||
spin_unlock(&lock);
|
||||
}
|
||||
|
||||
void report_prefix_pushf(const char *prefix_fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
unsigned int len;
|
||||
int start;
|
||||
|
||||
spin_lock(&lock);
|
||||
|
||||
len = strlen(prefixes);
|
||||
assert_msg(len < sizeof(prefixes), "%d >= %zu", len, sizeof(prefixes));
|
||||
start = len;
|
||||
|
||||
va_start(va, prefix_fmt);
|
||||
len += vsnprintf(&prefixes[len], sizeof(prefixes) - len, prefix_fmt,
|
||||
va);
|
||||
va_end(va);
|
||||
assert_msg(len < sizeof(prefixes), "%d >= %zu", len, sizeof(prefixes));
|
||||
|
||||
assert_msg(!strstr(&prefixes[start], PREFIX_DELIMITER),
|
||||
"Prefix \"%s\" contains delimiter \"" PREFIX_DELIMITER "\"",
|
||||
&prefixes[start]);
|
||||
|
||||
len += snprintf(&prefixes[len], sizeof(prefixes) - len,
|
||||
PREFIX_DELIMITER);
|
||||
assert_msg(len < sizeof(prefixes), "%d >= %zu", len, sizeof(prefixes));
|
||||
|
||||
spin_unlock(&lock);
|
||||
}
|
||||
|
||||
void report_prefix_push(const char *prefix)
|
||||
{
|
||||
report_prefix_pushf("%s", prefix);
|
||||
}
|
||||
|
||||
void report_prefix_pop(void)
|
||||
{
|
||||
char *p, *q;
|
||||
|
|
@ -34,9 +69,9 @@ void report_prefix_pop(void)
|
|||
if (!*prefixes)
|
||||
return;
|
||||
|
||||
for (p = prefixes, q = strstr(p, ": ") + 2;
|
||||
for (p = prefixes, q = strstr(p, PREFIX_DELIMITER) + 2;
|
||||
*q;
|
||||
p = q, q = strstr(p, ": ") + 2)
|
||||
p = q, q = strstr(p, PREFIX_DELIMITER) + 2)
|
||||
;
|
||||
*p = '\0';
|
||||
|
||||
|
|
@ -46,9 +81,9 @@ void report_prefix_pop(void)
|
|||
static void va_report(const char *msg_fmt,
|
||||
bool pass, bool xfail, bool skip, va_list va)
|
||||
{
|
||||
char *prefix = skip ? "SKIP"
|
||||
: xfail ? (pass ? "XPASS" : "XFAIL")
|
||||
: (pass ? "PASS" : "FAIL");
|
||||
const char *prefix = skip ? "SKIP"
|
||||
: xfail ? (pass ? "XPASS" : "XFAIL")
|
||||
: (pass ? "PASS" : "FAIL");
|
||||
|
||||
spin_lock(&lock);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
/*
|
||||
* setjmp/longjmp prototypes
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Library General Public License version 2.
|
||||
*/
|
||||
#ifndef LIBCFLAT_SETJMP_H
|
||||
#define LIBCFLAT_SETJMP_H 1
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
/*
|
||||
* stack related functions
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Library General Public License version 2.
|
||||
*/
|
||||
|
||||
#include <libcflat.h>
|
||||
#include <stack.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
/*
|
||||
* Header for stack related functions
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Library General Public License version 2.
|
||||
*/
|
||||
#ifndef _STACK_H_
|
||||
#define _STACK_H_
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
/*
|
||||
* libc string functions
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Library General Public License version 2.
|
||||
*/
|
||||
|
||||
#include "libcflat.h"
|
||||
|
||||
unsigned long strlen(const char *buf)
|
||||
|
|
@ -173,3 +180,44 @@ char *getenv(const char *name)
|
|||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Very simple glob matching. Allows '*' at beginning and end of pattern. */
|
||||
bool simple_glob(const char *text, const char *pattern)
|
||||
{
|
||||
bool star_start = false;
|
||||
bool star_end = false;
|
||||
size_t n = strlen(pattern);
|
||||
char copy[n + 1];
|
||||
|
||||
if (pattern[0] == '*') {
|
||||
pattern += 1;
|
||||
n -= 1;
|
||||
star_start = true;
|
||||
}
|
||||
|
||||
strcpy(copy, pattern);
|
||||
|
||||
if (n > 0 && pattern[n - 1] == '*') {
|
||||
n -= 1;
|
||||
copy[n] = '\0';
|
||||
star_end = true;
|
||||
}
|
||||
|
||||
if (star_start && star_end)
|
||||
return strstr(text, copy);
|
||||
|
||||
if (star_end)
|
||||
return strstr(text, copy) == text;
|
||||
|
||||
if (star_start) {
|
||||
size_t text_len = strlen(text);
|
||||
const char *suffix;
|
||||
|
||||
if (n > text_len)
|
||||
return false;
|
||||
suffix = text + text_len - n;
|
||||
return !strcmp(suffix, copy);
|
||||
}
|
||||
|
||||
return !strcmp(text, copy);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
/*
|
||||
* Header for libc string functions
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Library General Public License version 2.
|
||||
*/
|
||||
#ifndef __STRING_H
|
||||
#define __STRING_H
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* This work is licensed under the terms of the GNU LGPL, version 2.
|
||||
*/
|
||||
#include <libcflat.h>
|
||||
#include "util.h"
|
||||
|
||||
int parse_keyval(char *s, long *val)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
/*
|
||||
* virtqueue support adapted from the Linux kernel.
|
||||
*
|
||||
* Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
|
||||
* Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.
|
||||
* This work is licensed under the terms of the GNU GPL, version 2.
|
||||
*/
|
||||
#include "libcflat.h"
|
||||
#include "devicetree.h"
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
/*
|
||||
* A minimal implementation of virtio-mmio. Adapted from the Linux Kernel.
|
||||
*
|
||||
* Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
|
||||
* Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.
|
||||
* This work is licensed under the terms of the GNU GPL, version 2.
|
||||
*/
|
||||
#include "libcflat.h"
|
||||
#include "asm/page.h"
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
/*
|
||||
* virtqueue support adapted from the Linux kernel.
|
||||
*
|
||||
* Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
|
||||
* Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.
|
||||
* This work is licensed under the terms of the GNU GPL, version 2.
|
||||
*/
|
||||
#include "libcflat.h"
|
||||
#include "asm/io.h"
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
* A minimal implementation of virtio.
|
||||
* Structures adapted from the Linux Kernel.
|
||||
*
|
||||
* Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
|
||||
* Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.
|
||||
* This work is licensed under the terms of the GNU GPL, version 2.
|
||||
*/
|
||||
#include "libcflat.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@
|
|||
#define PT64_NX_MASK (1ull << 63)
|
||||
#define PT_ADDR_MASK GENMASK_ULL(51, 12)
|
||||
|
||||
#define PT_AD_MASK (PT_ACCESSED_MASK | PT_DIRTY_MASK)
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define PAGE_LEVEL 4
|
||||
#define PGDIR_WIDTH 9
|
||||
|
|
|
|||
|
|
@ -1,11 +1,6 @@
|
|||
#ifndef __ASM_SPINLOCK_H
|
||||
#define __ASM_SPINLOCK_H
|
||||
|
||||
struct spinlock {
|
||||
int v;
|
||||
};
|
||||
|
||||
void spin_lock(struct spinlock *lock);
|
||||
void spin_unlock(struct spinlock *lock);
|
||||
#include <asm-generic/spinlock.h>
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ static void unhandled_exception(struct ex_regs *regs, bool cpu)
|
|||
cpu ? "cpu " : "", regs->vector,
|
||||
exception_mnemonic(regs->vector), regs->rip);
|
||||
if (regs->vector == 14)
|
||||
printf("PF at 0x%lx addr 0x%lx\n", regs->rip, read_cr2());
|
||||
printf("PF at %#lx addr %#lx\n", regs->rip, read_cr2());
|
||||
|
||||
printf("error_code=%04lx rflags=%08lx cs=%08lx\n"
|
||||
"rax=%016lx rcx=%016lx rdx=%016lx rbx=%016lx\n"
|
||||
|
|
@ -117,13 +117,16 @@ static void check_exception_table(struct ex_regs *regs)
|
|||
unhandled_exception(regs, false);
|
||||
}
|
||||
|
||||
static void (*exception_handlers[32])(struct ex_regs *regs);
|
||||
static handler exception_handlers[32];
|
||||
|
||||
|
||||
void handle_exception(u8 v, void (*func)(struct ex_regs *regs))
|
||||
handler handle_exception(u8 v, handler fn)
|
||||
{
|
||||
handler old;
|
||||
|
||||
old = exception_handlers[v];
|
||||
if (v < 32)
|
||||
exception_handlers[v] = func;
|
||||
exception_handlers[v] = fn;
|
||||
return old;
|
||||
}
|
||||
|
||||
#ifndef __x86_64__
|
||||
|
|
@ -262,19 +265,6 @@ bool exception_rflags_rf(void)
|
|||
static char intr_alt_stack[4096];
|
||||
|
||||
#ifndef __x86_64__
|
||||
/*
|
||||
* GDT, with 6 entries:
|
||||
* 0x00 - NULL descriptor
|
||||
* 0x08 - Code segment (ring 0)
|
||||
* 0x10 - Data segment (ring 0)
|
||||
* 0x18 - Not present code segment (ring 0)
|
||||
* 0x20 - Code segment (ring 3)
|
||||
* 0x28 - Data segment (ring 3)
|
||||
* 0x30 - Interrupt task
|
||||
* 0x38 to 0x78 - Free to use for test cases
|
||||
* 0x80 - Primary task (CPU 0)
|
||||
*/
|
||||
|
||||
void set_gdt_entry(int sel, u32 base, u32 limit, u8 access, u8 gran)
|
||||
{
|
||||
int num = sel >> 3;
|
||||
|
|
@ -385,19 +375,21 @@ static void exception_handler(struct ex_regs *regs)
|
|||
/* longjmp must happen after iret, so do not do it now. */
|
||||
exception = true;
|
||||
regs->rip = (unsigned long)&exception_handler_longjmp;
|
||||
regs->cs = read_cs();
|
||||
}
|
||||
|
||||
bool test_for_exception(unsigned int ex, void (*trigger_func)(void *data),
|
||||
void *data)
|
||||
{
|
||||
handler old;
|
||||
jmp_buf jmpbuf;
|
||||
int ret;
|
||||
|
||||
handle_exception(ex, exception_handler);
|
||||
old = handle_exception(ex, exception_handler);
|
||||
ret = set_exception_jmpbuf(jmpbuf);
|
||||
if (ret == 0)
|
||||
trigger_func(data);
|
||||
handle_exception(ex, NULL);
|
||||
handle_exception(ex, old);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ struct ex_regs {
|
|||
unsigned long rflags;
|
||||
};
|
||||
|
||||
typedef void (*handler)(struct ex_regs *regs);
|
||||
|
||||
typedef struct {
|
||||
u16 prev;
|
||||
u16 res1;
|
||||
|
|
@ -85,24 +87,59 @@ typedef struct __attribute__((packed)) {
|
|||
#define UD_VECTOR 6
|
||||
#define GP_VECTOR 13
|
||||
|
||||
#define KERNEL_CS 0x08
|
||||
#define KERNEL_DS 0x10
|
||||
#define NP_SEL 0x18
|
||||
#define USER_CS 0x23
|
||||
#define USER_DS 0x2b
|
||||
/*
|
||||
* selector 32-bit 64-bit
|
||||
* 0x00 NULL descriptor NULL descriptor
|
||||
* 0x08 ring-0 code segment (32-bit) ring-0 code segment (64-bit)
|
||||
* 0x10 ring-0 data segment (32-bit) ring-0 data segment (32/64-bit)
|
||||
* 0x18 ring-0 code segment (P=0) ring-0 code segment (64-bit, P=0)
|
||||
* 0x20 intr_alt_stack TSS ring-0 code segment (32-bit)
|
||||
* 0x28 ring-0 code segment (16-bit) same
|
||||
* 0x30 ring-0 data segment (16-bit) same
|
||||
* 0x38 (0x3b) ring-3 code segment (32-bit) same
|
||||
* 0x40 (0x43) ring-3 data segment (32-bit) ring-3 data segment (32/64-bit)
|
||||
* 0x48 (0x4b) **unused** ring-3 code segment (64-bit)
|
||||
* 0x50--0x78 free to use for test cases same
|
||||
* 0x80 primary TSS (CPU 0) same
|
||||
*
|
||||
* Note that the same segment can be used for 32-bit and 64-bit data segments
|
||||
* (the L bit is only defined for code segments)
|
||||
*
|
||||
* Selectors 0x08-0x10 and 0x3b-0x4b are set up for use with the SYSCALL
|
||||
* and SYSRET instructions.
|
||||
*/
|
||||
|
||||
#define KERNEL_CS 0x08
|
||||
#define KERNEL_DS 0x10
|
||||
#define NP_SEL 0x18
|
||||
#ifdef __x86_64__
|
||||
#define KERNEL_CS32 0x20
|
||||
#else
|
||||
#define TSS_INTR 0x20
|
||||
#endif
|
||||
#define KERNEL_CS16 0x28
|
||||
#define KERNEL_DS16 0x30
|
||||
#define USER_CS32 0x3b
|
||||
#define USER_DS 0x43
|
||||
#ifdef __x86_64__
|
||||
#define USER_CS64 0x4b
|
||||
#endif
|
||||
|
||||
/* Synonyms */
|
||||
#define KERNEL_DS32 KERNEL_DS
|
||||
#define USER_DS32 USER_DS
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define KERNEL_CS64 KERNEL_CS
|
||||
#define USER_CS USER_CS64
|
||||
#define KERNEL_DS64 KERNEL_DS
|
||||
#define KERNEL_CS32 0x30
|
||||
#define KERNEL_DS32 0x38
|
||||
#define KERNEL_CS16 0x40
|
||||
#define KERNEL_DS16 0x48
|
||||
#define USER_DS64 USER_DS
|
||||
#else
|
||||
#define KERNEL_CS32 KERNEL_CS
|
||||
#define KERNEL_DS32 KERNEL_DS
|
||||
#define USER_CS USER_CS32
|
||||
#endif
|
||||
#define TSS_INTR 0x50
|
||||
#define FIRST_SPARE_SEL 0x58
|
||||
|
||||
#define FIRST_SPARE_SEL 0x50
|
||||
#define TSS_MAIN 0x80
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -153,7 +190,7 @@ void set_idt_dpl(int vec, u16 dpl);
|
|||
void set_gdt_entry(int sel, u32 base, u32 limit, u8 access, u8 gran);
|
||||
void set_intr_alt_stack(int e, void *fn);
|
||||
void print_current_tss_info(void);
|
||||
void handle_exception(u8 v, void (*func)(struct ex_regs *regs));
|
||||
handler handle_exception(u8 v, handler fn);
|
||||
|
||||
bool test_for_exception(unsigned int ex, void (*trigger_func)(void *data),
|
||||
void *data);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
static struct spinlock lock;
|
||||
|
||||
uint64_t fwcfg_get_u(uint16_t index, int bytes)
|
||||
static uint64_t fwcfg_get_u(uint16_t index, int bytes)
|
||||
{
|
||||
uint64_t r = 0;
|
||||
uint8_t b;
|
||||
|
|
|
|||
|
|
@ -115,9 +115,9 @@ static void vtd_dump_init_info(void)
|
|||
/* Major version >= 1 */
|
||||
assert(((version >> 3) & 0xf) >= 1);
|
||||
|
||||
printf("VT-d version: 0x%x\n", version);
|
||||
printf(" cap: 0x%016lx\n", vtd_readq(DMAR_CAP_REG));
|
||||
printf(" ecap: 0x%016lx\n", vtd_readq(DMAR_ECAP_REG));
|
||||
printf("VT-d version: %#x\n", version);
|
||||
printf(" cap: %#018lx\n", vtd_readq(DMAR_CAP_REG));
|
||||
printf(" ecap: %#018lx\n", vtd_readq(DMAR_ECAP_REG));
|
||||
}
|
||||
|
||||
static void vtd_setup_root_table(void)
|
||||
|
|
@ -127,7 +127,7 @@ static void vtd_setup_root_table(void)
|
|||
memset(root, 0, PAGE_SIZE);
|
||||
vtd_writeq(DMAR_RTADDR_REG, virt_to_phys(root));
|
||||
vtd_gcmd_or(VTD_GCMD_ROOT);
|
||||
printf("DMAR table address: 0x%016lx\n", vtd_root_table());
|
||||
printf("DMAR table address: %#018lx\n", vtd_root_table());
|
||||
}
|
||||
|
||||
static void vtd_setup_ir_table(void)
|
||||
|
|
@ -138,7 +138,7 @@ static void vtd_setup_ir_table(void)
|
|||
/* 0xf stands for table size (2^(0xf+1) == 65536) */
|
||||
vtd_writeq(DMAR_IRTA_REG, virt_to_phys(root) | 0xf);
|
||||
vtd_gcmd_or(VTD_GCMD_IR_TABLE);
|
||||
printf("IR table address: 0x%016lx\n", vtd_ir_table());
|
||||
printf("IR table address: %#018lx\n", vtd_ir_table());
|
||||
}
|
||||
|
||||
static void vtd_install_pte(vtd_pte_t *root, iova_t iova,
|
||||
|
|
@ -219,14 +219,14 @@ void vtd_map_range(uint16_t sid, iova_t iova, phys_addr_t pa, size_t size)
|
|||
ce->present = 1;
|
||||
/* No error reporting yet */
|
||||
ce->disable_fault_report = 1;
|
||||
printf("allocated vt-d context entry for devfn 0x%x\n",
|
||||
printf("allocated vt-d context entry for devfn %#x\n",
|
||||
devfn);
|
||||
} else
|
||||
slptptr = phys_to_virt(ce->slptptr << VTD_PAGE_SHIFT);
|
||||
|
||||
while (size) {
|
||||
/* TODO: currently we only map 4K pages (level = 1) */
|
||||
printf("map 4K page IOVA 0x%lx to 0x%lx (sid=0x%04x)\n",
|
||||
printf("map 4K page IOVA %#lx to %#lx (sid=%#06x)\n",
|
||||
iova, pa, sid);
|
||||
vtd_install_pte(slptptr, iova, pa, 1);
|
||||
size -= VTD_PAGE_SIZE;
|
||||
|
|
@ -324,7 +324,7 @@ bool vtd_setup_msi(struct pci_dev *dev, int vector, int dest_id)
|
|||
msi_addr.head = 0xfee;
|
||||
msi_data.subhandle = 0;
|
||||
|
||||
printf("%s: msi_addr=0x%" PRIx64 ", msi_data=0x%x\n", __func__,
|
||||
printf("%s: msi_addr=%#" PRIx64 ", msi_data=%#x\n", __func__,
|
||||
*(uint64_t *)&msi_addr, *(uint32_t *)&msi_data);
|
||||
|
||||
return pci_setup_msi(dev, *(uint64_t *)&msi_addr,
|
||||
|
|
|
|||
|
|
@ -30,13 +30,18 @@
|
|||
#define X86_CR4_SMAP 0x00200000
|
||||
#define X86_CR4_PKE 0x00400000
|
||||
|
||||
#define X86_EFLAGS_CF 0x00000001
|
||||
#define X86_EFLAGS_PF 0x00000004
|
||||
#define X86_EFLAGS_AF 0x00000010
|
||||
#define X86_EFLAGS_ZF 0x00000040
|
||||
#define X86_EFLAGS_SF 0x00000080
|
||||
#define X86_EFLAGS_OF 0x00000800
|
||||
#define X86_EFLAGS_AC 0x00040000
|
||||
#define X86_EFLAGS_CF 0x00000001
|
||||
#define X86_EFLAGS_FIXED 0x00000002
|
||||
#define X86_EFLAGS_PF 0x00000004
|
||||
#define X86_EFLAGS_AF 0x00000010
|
||||
#define X86_EFLAGS_ZF 0x00000040
|
||||
#define X86_EFLAGS_SF 0x00000080
|
||||
#define X86_EFLAGS_TF 0x00000100
|
||||
#define X86_EFLAGS_IF 0x00000200
|
||||
#define X86_EFLAGS_DF 0x00000400
|
||||
#define X86_EFLAGS_OF 0x00000800
|
||||
#define X86_EFLAGS_NT 0x00004000
|
||||
#define X86_EFLAGS_AC 0x00040000
|
||||
|
||||
#define X86_IA32_EFER 0xc0000080
|
||||
#define X86_EFER_LMA (1UL << 8)
|
||||
|
|
@ -430,4 +435,9 @@ static inline void write_pkru(u32 pkru)
|
|||
: : "a" (eax), "c" (ecx), "d" (edx));
|
||||
}
|
||||
|
||||
static inline bool is_canonical(u64 addr)
|
||||
{
|
||||
return (s64)(addr << 16) >> 16 == addr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
|
||||
#include <libcflat.h>
|
||||
#include "processor.h"
|
||||
#include "atomic.h"
|
||||
#include "smp.h"
|
||||
#include "apic.h"
|
||||
#include "fwcfg.h"
|
||||
|
|
@ -15,6 +17,7 @@ static void *volatile ipi_data;
|
|||
static volatile int ipi_done;
|
||||
static volatile bool ipi_wait;
|
||||
static int _cpu_count;
|
||||
static atomic_t active_cpus;
|
||||
|
||||
static __attribute__((used)) void ipi()
|
||||
{
|
||||
|
|
@ -27,6 +30,7 @@ static __attribute__((used)) void ipi()
|
|||
apic_write(APIC_EOI, 0);
|
||||
}
|
||||
function(data);
|
||||
atomic_dec(&active_cpus);
|
||||
if (wait) {
|
||||
ipi_done = 1;
|
||||
apic_write(APIC_EOI, 0);
|
||||
|
|
@ -43,22 +47,6 @@ asm (
|
|||
#endif
|
||||
);
|
||||
|
||||
void spin_lock(struct spinlock *lock)
|
||||
{
|
||||
int v = 1;
|
||||
|
||||
do {
|
||||
asm volatile ("xchg %1, %0" : "+m"(lock->v), "+r"(v));
|
||||
} while (v);
|
||||
asm volatile ("" : : : "memory");
|
||||
}
|
||||
|
||||
void spin_unlock(struct spinlock *lock)
|
||||
{
|
||||
asm volatile ("" : : : "memory");
|
||||
lock->v = 0;
|
||||
}
|
||||
|
||||
int cpu_count(void)
|
||||
{
|
||||
return _cpu_count;
|
||||
|
|
@ -84,6 +72,7 @@ static void __on_cpu(int cpu, void (*function)(void *data), void *data,
|
|||
if (cpu == smp_id())
|
||||
function(data);
|
||||
else {
|
||||
atomic_inc(&active_cpus);
|
||||
ipi_done = 0;
|
||||
ipi_function = function;
|
||||
ipi_data = data;
|
||||
|
|
@ -107,6 +96,21 @@ void on_cpu_async(int cpu, void (*function)(void *data), void *data)
|
|||
__on_cpu(cpu, function, data, 0);
|
||||
}
|
||||
|
||||
void on_cpus(void (*function)(void *data), void *data)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for (cpu = cpu_count() - 1; cpu >= 0; --cpu)
|
||||
on_cpu_async(cpu, function, data);
|
||||
|
||||
while (cpus_active() > 1)
|
||||
pause();
|
||||
}
|
||||
|
||||
int cpus_active(void)
|
||||
{
|
||||
return atomic_read(&active_cpus);
|
||||
}
|
||||
|
||||
void smp_init(void)
|
||||
{
|
||||
|
|
@ -122,4 +126,5 @@ void smp_init(void)
|
|||
for (i = 1; i < cpu_count(); ++i)
|
||||
on_cpu(i, setup_smp_id, 0);
|
||||
|
||||
atomic_inc(&active_cpus);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ void smp_init(void);
|
|||
|
||||
int cpu_count(void);
|
||||
int smp_id(void);
|
||||
int cpus_active(void);
|
||||
void on_cpu(int cpu, void (*function)(void *data), void *data);
|
||||
void on_cpu_async(int cpu, void (*function)(void *data), void *data);
|
||||
void on_cpus(void (*function)(void *data), void *data);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -7,12 +7,29 @@ static void *vfree_top = 0;
|
|||
|
||||
static void free_memory(void *mem, unsigned long size)
|
||||
{
|
||||
while (size >= PAGE_SIZE) {
|
||||
*(void **)mem = free;
|
||||
void *end;
|
||||
|
||||
assert_msg((unsigned long) mem % PAGE_SIZE == 0,
|
||||
"mem not page aligned: %p", mem);
|
||||
|
||||
assert_msg(size % PAGE_SIZE == 0, "size not page aligned: %#lx", size);
|
||||
|
||||
assert_msg(size == 0 || mem + size > mem,
|
||||
"mem + size overflow: %p + %#lx", mem, size);
|
||||
|
||||
if (size == 0) {
|
||||
free = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
free = mem;
|
||||
mem += PAGE_SIZE;
|
||||
size -= PAGE_SIZE;
|
||||
}
|
||||
end = mem + size;
|
||||
while (mem + PAGE_SIZE != end) {
|
||||
*(void **)mem = (mem + PAGE_SIZE);
|
||||
mem += PAGE_SIZE;
|
||||
}
|
||||
|
||||
*(void **)mem = NULL;
|
||||
}
|
||||
|
||||
void *alloc_page()
|
||||
|
|
@ -28,6 +45,63 @@ void *alloc_page()
|
|||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocates (1 << order) physically contiguous and naturally aligned pages.
|
||||
* Returns NULL if there's no memory left.
|
||||
*/
|
||||
void *alloc_pages(unsigned long order)
|
||||
{
|
||||
/* Generic list traversal. */
|
||||
void *prev;
|
||||
void *curr = NULL;
|
||||
void *next = free;
|
||||
|
||||
/* Looking for a run of length (1 << order). */
|
||||
unsigned long run = 0;
|
||||
const unsigned long n = 1ul << order;
|
||||
const unsigned long align_mask = (n << PAGE_SHIFT) - 1;
|
||||
void *run_start = NULL;
|
||||
void *run_prev = NULL;
|
||||
unsigned long run_next_pa = 0;
|
||||
unsigned long pa;
|
||||
|
||||
assert(order < sizeof(unsigned long) * 8);
|
||||
|
||||
for (;;) {
|
||||
prev = curr;
|
||||
curr = next;
|
||||
next = curr ? *((void **) curr) : NULL;
|
||||
|
||||
if (!curr)
|
||||
return 0;
|
||||
|
||||
pa = virt_to_phys(curr);
|
||||
|
||||
if (run == 0) {
|
||||
if (!(pa & align_mask)) {
|
||||
run_start = curr;
|
||||
run_prev = prev;
|
||||
run_next_pa = pa + PAGE_SIZE;
|
||||
run = 1;
|
||||
}
|
||||
} else if (pa == run_next_pa) {
|
||||
run_next_pa += PAGE_SIZE;
|
||||
run += 1;
|
||||
} else {
|
||||
run = 0;
|
||||
}
|
||||
|
||||
if (run == n) {
|
||||
if (run_prev)
|
||||
*((void **) run_prev) = next;
|
||||
else
|
||||
free = next;
|
||||
return run_start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void free_page(void *page)
|
||||
{
|
||||
*(void **)page = free;
|
||||
|
|
@ -65,23 +139,62 @@ unsigned long *install_pte(unsigned long *cr3,
|
|||
return &pt[offset];
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds last PTE in the mapping of @virt that's at or above @lowest_level. The
|
||||
* returned PTE isn't necessarily present, but its parent is.
|
||||
*/
|
||||
struct pte_search find_pte_level(unsigned long *cr3, void *virt,
|
||||
int lowest_level)
|
||||
{
|
||||
unsigned long *pt = cr3, pte;
|
||||
unsigned offset;
|
||||
unsigned long shift;
|
||||
struct pte_search r;
|
||||
|
||||
assert(lowest_level >= 1 && lowest_level <= PAGE_LEVEL);
|
||||
|
||||
for (r.level = PAGE_LEVEL;; --r.level) {
|
||||
shift = (r.level - 1) * PGDIR_WIDTH + 12;
|
||||
offset = ((unsigned long)virt >> shift) & PGDIR_MASK;
|
||||
r.pte = &pt[offset];
|
||||
pte = *r.pte;
|
||||
|
||||
if (!(pte & PT_PRESENT_MASK))
|
||||
return r;
|
||||
|
||||
if ((r.level == 2 || r.level == 3) && (pte & PT_PAGE_SIZE_MASK))
|
||||
return r;
|
||||
|
||||
if (r.level == lowest_level)
|
||||
return r;
|
||||
|
||||
pt = phys_to_virt(pte & 0xffffffffff000ull);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the leaf PTE in the mapping of @virt (i.e., 4K PTE or a present huge
|
||||
* PTE). Returns NULL if no leaf PTE exists.
|
||||
*/
|
||||
unsigned long *get_pte(unsigned long *cr3, void *virt)
|
||||
{
|
||||
int level;
|
||||
unsigned long *pt = cr3, pte;
|
||||
unsigned offset;
|
||||
struct pte_search search;
|
||||
|
||||
for (level = PAGE_LEVEL; level > 1; --level) {
|
||||
offset = ((unsigned long)virt >> (((level-1) * PGDIR_WIDTH) + 12)) & PGDIR_MASK;
|
||||
pte = pt[offset];
|
||||
if (!(pte & PT_PRESENT_MASK))
|
||||
return NULL;
|
||||
if (level == 2 && (pte & PT_PAGE_SIZE_MASK))
|
||||
return &pt[offset];
|
||||
pt = phys_to_virt(pte & PT_ADDR_MASK);
|
||||
}
|
||||
offset = ((unsigned long)virt >> (((level-1) * PGDIR_WIDTH) + 12)) & PGDIR_MASK;
|
||||
return &pt[offset];
|
||||
search = find_pte_level(cr3, virt, 1);
|
||||
return found_leaf_pte(search) ? search.pte : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the PTE in the mapping of @virt at the given level @pte_level.
|
||||
* Returns NULL if the PT at @pte_level isn't present (i.e., the mapping at
|
||||
* @pte_level - 1 isn't present).
|
||||
*/
|
||||
unsigned long *get_pte_level(unsigned long *cr3, void *virt, int pte_level)
|
||||
{
|
||||
struct pte_search search;
|
||||
|
||||
search = find_pte_level(cr3, virt, pte_level);
|
||||
return search.level == pte_level ? search.pte : NULL;
|
||||
}
|
||||
|
||||
unsigned long *install_large_page(unsigned long *cr3,
|
||||
|
|
@ -99,6 +212,33 @@ unsigned long *install_page(unsigned long *cr3,
|
|||
return install_pte(cr3, 1, virt, phys | PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK, 0);
|
||||
}
|
||||
|
||||
void install_pages(unsigned long *cr3, unsigned long phys, unsigned long len,
|
||||
void *virt)
|
||||
{
|
||||
unsigned long max = (u64)len + (u64)phys;
|
||||
assert(phys % PAGE_SIZE == 0);
|
||||
assert((unsigned long) virt % PAGE_SIZE == 0);
|
||||
assert(len % PAGE_SIZE == 0);
|
||||
|
||||
while (phys + PAGE_SIZE <= max) {
|
||||
install_page(cr3, phys, virt);
|
||||
phys += PAGE_SIZE;
|
||||
virt = (char *) virt + PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
bool any_present_pages(unsigned long *cr3, void *virt, unsigned long len)
|
||||
{
|
||||
unsigned long max = (unsigned long) virt + len;
|
||||
unsigned long curr;
|
||||
|
||||
for (curr = (unsigned long) virt; curr < max; curr += PAGE_SIZE) {
|
||||
unsigned long *ptep = get_pte(cr3, (void *) curr);
|
||||
if (ptep && (*ptep & PT_PRESENT_MASK))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void setup_mmu_range(unsigned long *cr3, unsigned long start,
|
||||
unsigned long len)
|
||||
|
|
@ -110,10 +250,7 @@ static void setup_mmu_range(unsigned long *cr3, unsigned long start,
|
|||
install_large_page(cr3, phys, (void *)(ulong)phys);
|
||||
phys += LARGE_PAGE_SIZE;
|
||||
}
|
||||
while (phys + PAGE_SIZE <= max) {
|
||||
install_page(cr3, phys, (void *)(ulong)phys);
|
||||
phys += PAGE_SIZE;
|
||||
}
|
||||
install_pages(cr3, phys, max - phys, (void *)(ulong)phys);
|
||||
}
|
||||
|
||||
static void setup_mmu(unsigned long len)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,27 @@ void *alloc_vpage(void);
|
|||
void *alloc_vpages(ulong nr);
|
||||
uint64_t virt_to_phys_cr3(void *mem);
|
||||
|
||||
struct pte_search {
|
||||
int level;
|
||||
unsigned long *pte;
|
||||
};
|
||||
|
||||
static inline bool found_huge_pte(struct pte_search search)
|
||||
{
|
||||
return (search.level == 2 || search.level == 3) &&
|
||||
(*search.pte & PT_PRESENT_MASK) &&
|
||||
(*search.pte & PT_PAGE_SIZE_MASK);
|
||||
}
|
||||
|
||||
static inline bool found_leaf_pte(struct pte_search search)
|
||||
{
|
||||
return search.level == 1 || found_huge_pte(search);
|
||||
}
|
||||
|
||||
struct pte_search find_pte_level(unsigned long *cr3, void *virt,
|
||||
int lowest_level);
|
||||
unsigned long *get_pte(unsigned long *cr3, void *virt);
|
||||
unsigned long *get_pte_level(unsigned long *cr3, void *virt, int pte_level);
|
||||
unsigned long *install_pte(unsigned long *cr3,
|
||||
int pte_level,
|
||||
void *virt,
|
||||
|
|
@ -22,10 +42,18 @@ unsigned long *install_pte(unsigned long *cr3,
|
|||
unsigned long *pt_page);
|
||||
|
||||
void *alloc_page();
|
||||
void *alloc_pages(unsigned long order);
|
||||
void free_page(void *page);
|
||||
|
||||
unsigned long *install_large_page(unsigned long *cr3,unsigned long phys,
|
||||
void *virt);
|
||||
unsigned long *install_page(unsigned long *cr3, unsigned long phys, void *virt);
|
||||
void install_pages(unsigned long *cr3, unsigned long phys, unsigned long len,
|
||||
void *virt);
|
||||
bool any_present_pages(unsigned long *cr3, void *virt, unsigned long len);
|
||||
|
||||
static inline void *current_page_table(void)
|
||||
{
|
||||
return phys_to_virt(read_cr3());
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
include $(TEST_DIR)/Makefile.$(ARCH)
|
||||
include $(SRCDIR)/$(TEST_DIR)/Makefile.$(ARCH)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#This is a make file with common rules for both x86 & x86-64
|
||||
|
||||
all: test_cases
|
||||
all: directories test_cases
|
||||
|
||||
cflatobjs += lib/pci.o
|
||||
cflatobjs += lib/pci-edu.o
|
||||
|
|
@ -16,11 +16,13 @@ cflatobjs += lib/x86/isr.o
|
|||
cflatobjs += lib/x86/acpi.o
|
||||
cflatobjs += lib/x86/stack.o
|
||||
|
||||
$(libcflat): LDFLAGS += -nostdlib
|
||||
$(libcflat): CFLAGS += -ffreestanding -I lib
|
||||
OBJDIRS += lib/x86
|
||||
|
||||
CFLAGS += -m$(bits)
|
||||
CFLAGS += -O1
|
||||
$(libcflat): LDFLAGS += -nostdlib
|
||||
$(libcflat): CFLAGS += -ffreestanding -I $(SRCDIR)/lib -I lib
|
||||
|
||||
COMMON_CFLAGS += -m$(bits)
|
||||
COMMON_CFLAGS += -O1
|
||||
|
||||
# stack.o relies on frame pointers.
|
||||
KEEP_FRAME_POINTER := y
|
||||
|
|
@ -31,8 +33,8 @@ libgcc := $(shell $(CC) -m$(bits) --print-libgcc-file-name)
|
|||
.PRECIOUS: %.elf %.o
|
||||
|
||||
FLATLIBS = lib/libcflat.a $(libgcc)
|
||||
%.elf: %.o $(FLATLIBS) x86/flat.lds $(cstart.o)
|
||||
$(CC) $(CFLAGS) -nostdlib -o $@ -Wl,-T,x86/flat.lds \
|
||||
%.elf: %.o $(FLATLIBS) $(SRCDIR)/x86/flat.lds $(cstart.o)
|
||||
$(CC) $(CFLAGS) -nostdlib -o $@ -Wl,-T,$(SRCDIR)/x86/flat.lds \
|
||||
$(filter %.o, $^) $(FLATLIBS)
|
||||
|
||||
%.flat: %.elf
|
||||
|
|
@ -47,19 +49,20 @@ tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \
|
|||
$(TEST_DIR)/tsc_adjust.flat $(TEST_DIR)/asyncpf.flat \
|
||||
$(TEST_DIR)/init.flat $(TEST_DIR)/smap.flat \
|
||||
$(TEST_DIR)/hyperv_synic.flat $(TEST_DIR)/hyperv_stimer.flat \
|
||||
$(TEST_DIR)/hyperv_connections.flat \
|
||||
|
||||
ifdef API
|
||||
tests-common += api/api-sample
|
||||
tests-common += api/dirty-log
|
||||
tests-common += api/dirty-log-perf
|
||||
tests-api = api/api-sample api/dirty-log api/dirty-log-perf
|
||||
|
||||
OBJDIRS += api
|
||||
endif
|
||||
|
||||
test_cases: $(tests-common) $(tests)
|
||||
test_cases: $(tests-common) $(tests) $(tests-api)
|
||||
|
||||
$(TEST_DIR)/%.o: CFLAGS += -std=gnu99 -ffreestanding -I lib -I lib/x86
|
||||
$(TEST_DIR)/%.o: CFLAGS += -std=gnu99 -ffreestanding -I $(SRCDIR)/lib -I $(SRCDIR)/lib/x86 -I lib
|
||||
|
||||
$(TEST_DIR)/realmode.elf: $(TEST_DIR)/realmode.o
|
||||
$(CC) -m32 -nostdlib -o $@ -Wl,-T,$(TEST_DIR)/realmode.lds $^
|
||||
$(CC) -m32 -nostdlib -o $@ -Wl,-T,$(SRCDIR)/$(TEST_DIR)/realmode.lds $^
|
||||
|
||||
$(TEST_DIR)/realmode.o: bits = 32
|
||||
|
||||
|
|
@ -69,20 +72,19 @@ $(TEST_DIR)/hyperv_synic.elf: $(TEST_DIR)/hyperv.o
|
|||
|
||||
$(TEST_DIR)/hyperv_stimer.elf: $(TEST_DIR)/hyperv.o
|
||||
|
||||
$(TEST_DIR)/hyperv_connections.elf: $(TEST_DIR)/hyperv.o
|
||||
|
||||
arch_clean:
|
||||
$(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat $(TEST_DIR)/*.elf \
|
||||
$(TEST_DIR)/.*.d lib/x86/.*.d
|
||||
$(TEST_DIR)/.*.d lib/x86/.*.d \
|
||||
$(tests-api) api/*.o api/*.a api/.*.d
|
||||
|
||||
api/%.o: CFLAGS += -m32
|
||||
api/%.o: CXXFLAGS += -m32 -std=gnu++11
|
||||
|
||||
api/%: LDLIBS += -lstdc++ -lboost_thread -lpthread -lrt
|
||||
api/%: LDLIBS += -lstdc++ -lpthread -lrt
|
||||
api/%: LDFLAGS += -m32
|
||||
|
||||
api/libapi.a: api/kvmxx.o api/identity.o api/exception.o api/memmap.o
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
api/api-sample: api/api-sample.o api/libapi.a
|
||||
|
||||
api/dirty-log: api/dirty-log.o api/libapi.a
|
||||
|
||||
api/dirty-log-perf: api/dirty-log-perf.o api/libapi.a
|
||||
$(tests-api) : % : %.o api/libapi.a
|
||||
|
|
|
|||
|
|
@ -30,4 +30,4 @@ tests += $(TEST_DIR)/tscdeadline_latency.flat
|
|||
#tests += $(TEST_DIR)/intel-iommu.flat
|
||||
|
||||
|
||||
include $(TEST_DIR)/Makefile.common
|
||||
include $(SRCDIR)/$(TEST_DIR)/Makefile.common
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
cstart.o = $(TEST_DIR)/cstart64.o
|
||||
bits = 64
|
||||
ldarch = elf64-x86-64
|
||||
CFLAGS += -mno-red-zone
|
||||
COMMON_CFLAGS += -mno-red-zone
|
||||
|
||||
cflatobjs += lib/x86/setjmp64.o
|
||||
cflatobjs += lib/x86/intel-iommu.o
|
||||
|
|
@ -12,12 +12,13 @@ tests = $(TEST_DIR)/access.flat $(TEST_DIR)/apic.flat \
|
|||
$(TEST_DIR)/pcid.flat $(TEST_DIR)/debug.flat \
|
||||
$(TEST_DIR)/ioapic.flat $(TEST_DIR)/memory.flat \
|
||||
$(TEST_DIR)/pku.flat $(TEST_DIR)/hyperv_clock.flat
|
||||
tests += $(TEST_DIR)/syscall.flat
|
||||
tests += $(TEST_DIR)/svm.flat
|
||||
tests += $(TEST_DIR)/vmx.flat
|
||||
tests += $(TEST_DIR)/tscdeadline_latency.flat
|
||||
tests += $(TEST_DIR)/intel-iommu.flat
|
||||
|
||||
include $(TEST_DIR)/Makefile.common
|
||||
include $(SRCDIR)/$(TEST_DIR)/Makefile.common
|
||||
|
||||
$(TEST_DIR)/hyperv_clock.elf: $(TEST_DIR)/hyperv_clock.o
|
||||
|
||||
|
|
|
|||
|
|
@ -52,13 +52,13 @@ static void pf_isr(struct ex_regs *r)
|
|||
|
||||
switch (reason) {
|
||||
case 0:
|
||||
report("unexpected #PF at %p", false, read_cr2());
|
||||
report("unexpected #PF at %#lx", false, read_cr2());
|
||||
break;
|
||||
case KVM_PV_REASON_PAGE_NOT_PRESENT:
|
||||
phys = virt_to_phys_cr3(virt);
|
||||
install_pte(phys_to_virt(read_cr3()), 1, virt, phys, 0);
|
||||
write_cr3(read_cr3());
|
||||
report("Got not present #PF token %x virt addr %p phys addr %p",
|
||||
report("Got not present #PF token %lx virt addr %p phys addr %#" PRIx64,
|
||||
true, read_cr2(), virt, phys);
|
||||
while(phys) {
|
||||
safe_halt(); /* enables irq */
|
||||
|
|
@ -66,7 +66,7 @@ static void pf_isr(struct ex_regs *r)
|
|||
}
|
||||
break;
|
||||
case KVM_PV_REASON_PAGE_READY:
|
||||
report("Got present #PF token %x", true, read_cr2());
|
||||
report("Got present #PF token %lx", true, read_cr2());
|
||||
if ((uint32_t)read_cr2() == ~0)
|
||||
break;
|
||||
install_pte(phys_to_virt(read_cr3()), 1, virt, phys | PT_PRESENT_MASK | PT_WRITABLE_MASK, 0);
|
||||
|
|
|
|||
|
|
@ -34,14 +34,14 @@ gdt32:
|
|||
.quad 0x00cf9b000000ffff // flat 32-bit code segment
|
||||
.quad 0x00cf93000000ffff // flat 32-bit data segment
|
||||
.quad 0x00cf1b000000ffff // flat 32-bit code segment, not present
|
||||
.quad 0x00cffb000000ffff // 64-bit code segment (user)
|
||||
.quad 0x00cff3000000ffff // 64-bit data segment (user)
|
||||
.quad 0 // TSS for task gates
|
||||
.quad 0x008f9b000000FFFF // 16-bit code segment
|
||||
.quad 0x008f93000000FFFF // 16-bit data segment
|
||||
.quad 0x00cffb000000ffff // 32-bit code segment (user)
|
||||
.quad 0x00cff3000000ffff // 32-bit data segment (user)
|
||||
.quad 0 // unused
|
||||
|
||||
.quad 0 // 10 spare selectors
|
||||
.quad 0
|
||||
.quad 0
|
||||
.quad 0
|
||||
.quad 0
|
||||
.quad 0 // 6 spare selectors
|
||||
.quad 0
|
||||
.quad 0
|
||||
.quad 0
|
||||
|
|
|
|||
|
|
@ -53,14 +53,14 @@ gdt64_desc:
|
|||
gdt64:
|
||||
.quad 0
|
||||
.quad 0x00af9b000000ffff // 64-bit code segment
|
||||
.quad 0x00cf93000000ffff // 64-bit data segment
|
||||
.quad 0x00cf93000000ffff // 32/64-bit data segment
|
||||
.quad 0x00af1b000000ffff // 64-bit code segment, not present
|
||||
.quad 0x00affb000000ffff // 64-bit code segment (user)
|
||||
.quad 0x00cff3000000ffff // 64-bit data segment (user)
|
||||
.quad 0x00cf9b000000ffff // 32-bit code segment
|
||||
.quad 0x00cf92000000ffff // 32-bit data segment
|
||||
.quad 0x008F9A000000FFFF // 16-bit code segment
|
||||
.quad 0x008F92000000FFFF // 16-bit data segment
|
||||
.quad 0x008f9b000000FFFF // 16-bit code segment
|
||||
.quad 0x008f93000000FFFF // 16-bit data segment
|
||||
.quad 0x00cffb000000ffff // 32-bit code segment (user)
|
||||
.quad 0x00cff3000000ffff // 32/64-bit data segment (user)
|
||||
.quad 0x00affb000000ffff // 64-bit code segment (user)
|
||||
|
||||
.quad 0 // 6 spare selectors
|
||||
.quad 0
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ static void nmi_iret_isr(struct ex_regs *r)
|
|||
static void tirq0(isr_regs_t *r)
|
||||
{
|
||||
printf("irq0 running\n");
|
||||
if (test_count != 0)
|
||||
if (test_count == 1)
|
||||
test_count++;
|
||||
eoi();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,70 @@
|
|||
#include "hyperv.h"
|
||||
#include "asm/io.h"
|
||||
#include "smp.h"
|
||||
|
||||
static void synic_ctl(u8 ctl, u8 vcpu_id, u8 sint)
|
||||
enum {
|
||||
HV_TEST_DEV_SINT_ROUTE_CREATE = 1,
|
||||
HV_TEST_DEV_SINT_ROUTE_DESTROY,
|
||||
HV_TEST_DEV_SINT_ROUTE_SET_SINT,
|
||||
HV_TEST_DEV_MSG_CONN_CREATE,
|
||||
HV_TEST_DEV_MSG_CONN_DESTROY,
|
||||
HV_TEST_DEV_EVT_CONN_CREATE,
|
||||
HV_TEST_DEV_EVT_CONN_DESTROY,
|
||||
};
|
||||
|
||||
static void synic_ctl(u32 ctl, u32 vcpu_id, u32 sint, u32 conn_id)
|
||||
{
|
||||
outl((ctl << 16)|((vcpu_id) << 8)|sint, 0x3000);
|
||||
outl((conn_id << 24) | (ctl << 16) | (vcpu_id << 8) | sint, 0x3000);
|
||||
}
|
||||
|
||||
void synic_sint_create(int vcpu, int sint, int vec, bool auto_eoi)
|
||||
static void sint_enable(u8 sint, u8 vec, bool auto_eoi)
|
||||
{
|
||||
wrmsr(HV_X64_MSR_SINT0 + sint,
|
||||
(u64)vec | ((auto_eoi) ? HV_SYNIC_SINT_AUTO_EOI : 0));
|
||||
synic_ctl(HV_TEST_DEV_SINT_ROUTE_CREATE, vcpu, sint);
|
||||
(u64)vec | (auto_eoi ? HV_SYNIC_SINT_AUTO_EOI : 0));
|
||||
}
|
||||
|
||||
void synic_sint_set(int vcpu, int sint)
|
||||
static void sint_disable(u8 sint)
|
||||
{
|
||||
synic_ctl(HV_TEST_DEV_SINT_ROUTE_SET_SINT, vcpu, sint);
|
||||
wrmsr(HV_X64_MSR_SINT0 + sint, 0xff | HV_SYNIC_SINT_MASKED);
|
||||
}
|
||||
|
||||
void synic_sint_destroy(int vcpu, int sint)
|
||||
void synic_sint_create(u8 sint, u8 vec, bool auto_eoi)
|
||||
{
|
||||
wrmsr(HV_X64_MSR_SINT0 + sint, 0xFF|HV_SYNIC_SINT_MASKED);
|
||||
synic_ctl(HV_TEST_DEV_SINT_ROUTE_DESTROY, vcpu, sint);
|
||||
synic_ctl(HV_TEST_DEV_SINT_ROUTE_CREATE, smp_id(), sint, 0);
|
||||
sint_enable(sint, vec, auto_eoi);
|
||||
}
|
||||
|
||||
void synic_sint_set(u8 vcpu, u8 sint)
|
||||
{
|
||||
synic_ctl(HV_TEST_DEV_SINT_ROUTE_SET_SINT, vcpu, sint, 0);
|
||||
}
|
||||
|
||||
void synic_sint_destroy(u8 sint)
|
||||
{
|
||||
sint_disable(sint);
|
||||
synic_ctl(HV_TEST_DEV_SINT_ROUTE_DESTROY, smp_id(), sint, 0);
|
||||
}
|
||||
|
||||
void msg_conn_create(u8 sint, u8 vec, u8 conn_id)
|
||||
{
|
||||
synic_ctl(HV_TEST_DEV_MSG_CONN_CREATE, smp_id(), sint, conn_id);
|
||||
sint_enable(sint, vec, true);
|
||||
}
|
||||
|
||||
void msg_conn_destroy(u8 sint, u8 conn_id)
|
||||
{
|
||||
sint_disable(sint);
|
||||
synic_ctl(HV_TEST_DEV_MSG_CONN_DESTROY, 0, 0, conn_id);
|
||||
}
|
||||
|
||||
void evt_conn_create(u8 sint, u8 vec, u8 conn_id)
|
||||
{
|
||||
synic_ctl(HV_TEST_DEV_EVT_CONN_CREATE, smp_id(), sint, conn_id);
|
||||
sint_enable(sint, vec, true);
|
||||
}
|
||||
|
||||
void evt_conn_destroy(u8 sint, u8 conn_id)
|
||||
{
|
||||
sint_disable(sint);
|
||||
synic_ctl(HV_TEST_DEV_EVT_CONN_DESTROY, 0, 0, conn_id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@
|
|||
#define HV_X64_MSR_SYNIC_AVAILABLE (1 << 2)
|
||||
#define HV_X64_MSR_SYNTIMER_AVAILABLE (1 << 3)
|
||||
|
||||
#define HV_X64_MSR_GUEST_OS_ID 0x40000000
|
||||
#define HV_X64_MSR_HYPERCALL 0x40000001
|
||||
|
||||
#define HV_X64_MSR_TIME_REF_COUNT 0x40000020
|
||||
#define HV_X64_MSR_REFERENCE_TSC 0x40000021
|
||||
|
||||
|
|
@ -155,10 +158,29 @@ struct hv_message_page {
|
|||
struct hv_message sint_message[HV_SYNIC_SINT_COUNT];
|
||||
};
|
||||
|
||||
enum {
|
||||
HV_TEST_DEV_SINT_ROUTE_CREATE = 1,
|
||||
HV_TEST_DEV_SINT_ROUTE_DESTROY,
|
||||
HV_TEST_DEV_SINT_ROUTE_SET_SINT
|
||||
#define HV_EVENT_FLAGS_COUNT (256 * 8)
|
||||
|
||||
struct hv_event_flags {
|
||||
ulong flags[HV_EVENT_FLAGS_COUNT / (8 * sizeof(ulong))];
|
||||
};
|
||||
|
||||
struct hv_event_flags_page {
|
||||
struct hv_event_flags slot[HV_SYNIC_SINT_COUNT];
|
||||
};
|
||||
|
||||
#define HV_X64_MSR_HYPERCALL_ENABLE 0x1
|
||||
|
||||
#define HV_HYPERCALL_FAST (1u << 16)
|
||||
|
||||
#define HVCALL_POST_MESSAGE 0x5c
|
||||
#define HVCALL_SIGNAL_EVENT 0x5d
|
||||
|
||||
struct hv_input_post_message {
|
||||
u32 connectionid;
|
||||
u32 reserved;
|
||||
u32 message_type;
|
||||
u32 payload_size;
|
||||
u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
|
||||
};
|
||||
|
||||
static inline bool synic_supported(void)
|
||||
|
|
@ -176,9 +198,13 @@ static inline bool hv_time_ref_counter_supported(void)
|
|||
return cpuid(HYPERV_CPUID_FEATURES).a & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE;
|
||||
}
|
||||
|
||||
void synic_sint_create(int vcpu, int sint, int vec, bool auto_eoi);
|
||||
void synic_sint_set(int vcpu, int sint);
|
||||
void synic_sint_destroy(int vcpu, int sint);
|
||||
void synic_sint_create(u8 sint, u8 vec, bool auto_eoi);
|
||||
void synic_sint_set(u8 vcpu, u8 sint);
|
||||
void synic_sint_destroy(u8 sint);
|
||||
void msg_conn_create(u8 sint, u8 vec, u8 conn_id);
|
||||
void msg_conn_destroy(u8 sint, u8 conn_id);
|
||||
void evt_conn_create(u8 sint, u8 vec, u8 conn_id);
|
||||
void evt_conn_destroy(u8 sint, u8 conn_id);
|
||||
|
||||
struct hv_reference_tsc_page {
|
||||
uint32_t tsc_sequence;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ static inline u64 scale_delta(u64 delta, u64 mul_frac)
|
|||
u64 product, unused;
|
||||
|
||||
__asm__ (
|
||||
"mul %3"
|
||||
"mulq %3"
|
||||
: "=d" (product), "=a" (unused) : "1" (delta), "rm" ((u64)mul_frac) );
|
||||
|
||||
return product;
|
||||
|
|
@ -55,7 +55,6 @@ uint64_t hv_clock_read(void)
|
|||
return hvclock_tsc_to_ticks(&shadow, rdtsc());
|
||||
}
|
||||
|
||||
atomic_t cpus_left;
|
||||
bool ok[MAX_CPU];
|
||||
uint64_t loops[MAX_CPU];
|
||||
|
||||
|
|
@ -99,7 +98,6 @@ static void hv_clock_test(void *data)
|
|||
if (!got_drift)
|
||||
printf("delta on CPU %d was %d...%d\n", smp_id(), min_delta, max_delta);
|
||||
barrier();
|
||||
atomic_dec(&cpus_left);
|
||||
}
|
||||
|
||||
static void check_test(int ncpus)
|
||||
|
|
@ -107,13 +105,7 @@ static void check_test(int ncpus)
|
|||
int i;
|
||||
bool pass;
|
||||
|
||||
atomic_set(&cpus_left, ncpus);
|
||||
for (i = ncpus - 1; i >= 0; i--)
|
||||
on_cpu_async(i, hv_clock_test, NULL);
|
||||
|
||||
/* Wait for the end of other vcpu */
|
||||
while(atomic_read(&cpus_left))
|
||||
;
|
||||
on_cpus(hv_clock_test, NULL);
|
||||
|
||||
pass = true;
|
||||
for (i = ncpus - 1; i >= 0; i--)
|
||||
|
|
@ -134,7 +126,6 @@ static void hv_perf_test(void *data)
|
|||
} while(t < end);
|
||||
|
||||
loops[smp_id()] = local_loops;
|
||||
atomic_dec(&cpus_left);
|
||||
}
|
||||
|
||||
static void perf_test(int ncpus)
|
||||
|
|
@ -142,13 +133,7 @@ static void perf_test(int ncpus)
|
|||
int i;
|
||||
uint64_t total_loops;
|
||||
|
||||
atomic_set(&cpus_left, ncpus);
|
||||
for (i = ncpus - 1; i >= 0; i--)
|
||||
on_cpu_async(i, hv_perf_test, NULL);
|
||||
|
||||
/* Wait for the end of other vcpu */
|
||||
while(atomic_read(&cpus_left))
|
||||
;
|
||||
on_cpus(hv_perf_test, NULL);
|
||||
|
||||
total_loops = 0;
|
||||
for (i = ncpus - 1; i >= 0; i--)
|
||||
|
|
@ -167,6 +152,10 @@ int main(int ac, char **av)
|
|||
setup_vm();
|
||||
smp_init();
|
||||
|
||||
ncpus = cpu_count();
|
||||
if (ncpus > MAX_CPU)
|
||||
report_abort("number cpus exceeds %d", MAX_CPU);
|
||||
|
||||
hv_clock = alloc_page();
|
||||
wrmsr(HV_X64_MSR_REFERENCE_TSC, (u64)(uintptr_t)hv_clock | 1);
|
||||
report("MSR value after enabling",
|
||||
|
|
@ -195,10 +184,6 @@ int main(int ac, char **av)
|
|||
"TSC reference %" PRId64" (delta %" PRId64")\n",
|
||||
ref2, ref2 - ref1, tsc2, t2, t2 - t1);
|
||||
|
||||
ncpus = cpu_count();
|
||||
if (ncpus > MAX_CPU)
|
||||
ncpus = MAX_CPU;
|
||||
|
||||
check_test(ncpus);
|
||||
perf_test(ncpus);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@
|
|||
#define SINT2_NUM 3
|
||||
#define ONE_MS_IN_100NS 10000
|
||||
|
||||
static atomic_t g_cpus_comp_count;
|
||||
static int g_cpus_count;
|
||||
static struct spinlock g_synic_alloc_lock;
|
||||
|
||||
struct stimer {
|
||||
|
|
@ -216,20 +214,13 @@ static void synic_disable(void)
|
|||
synic_free_page(svcpu->msg_page);
|
||||
}
|
||||
|
||||
static void cpu_comp(void)
|
||||
{
|
||||
atomic_inc(&g_cpus_comp_count);
|
||||
}
|
||||
|
||||
static void stimer_test_prepare(void *ctx)
|
||||
{
|
||||
int vcpu = smp_id();
|
||||
|
||||
write_cr3((ulong)ctx);
|
||||
synic_enable();
|
||||
synic_sint_create(vcpu, SINT1_NUM, SINT1_VEC, false);
|
||||
synic_sint_create(vcpu, SINT2_NUM, SINT2_VEC, true);
|
||||
cpu_comp();
|
||||
synic_sint_create(SINT1_NUM, SINT1_VEC, false);
|
||||
synic_sint_create(SINT2_NUM, SINT2_VEC, true);
|
||||
}
|
||||
|
||||
static void stimer_test_periodic(int vcpu, struct stimer *timer1,
|
||||
|
|
@ -280,6 +271,35 @@ static void stimer_test_auto_enable_periodic(int vcpu, struct stimer *timer)
|
|||
stimer_shutdown(timer);
|
||||
}
|
||||
|
||||
static void stimer_test_one_shot_busy(int vcpu, struct stimer *timer)
|
||||
{
|
||||
struct hv_message_page *msg_page = g_synic_vcpu[vcpu].msg_page;
|
||||
struct hv_message *msg = &msg_page->sint_message[timer->sint];
|
||||
|
||||
msg->header.message_type = HVMSG_TIMER_EXPIRED;
|
||||
wmb();
|
||||
|
||||
stimer_start(timer, false, false, ONE_MS_IN_100NS, SINT1_NUM);
|
||||
|
||||
do
|
||||
rmb();
|
||||
while (!msg->header.message_flags.msg_pending);
|
||||
|
||||
report("no timer fired while msg slot busy: vcpu %d",
|
||||
!atomic_read(&timer->fire_count), vcpu);
|
||||
|
||||
msg->header.message_type = HVMSG_NONE;
|
||||
wmb();
|
||||
wrmsr(HV_X64_MSR_EOM, 0);
|
||||
|
||||
while (atomic_read(&timer->fire_count) < 1) {
|
||||
pause();
|
||||
}
|
||||
report("timer resumed when msg slot released: vcpu %d", true, vcpu);
|
||||
|
||||
stimer_shutdown(timer);
|
||||
}
|
||||
|
||||
static void stimer_test(void *ctx)
|
||||
{
|
||||
int vcpu = smp_id();
|
||||
|
|
@ -295,33 +315,17 @@ static void stimer_test(void *ctx)
|
|||
stimer_test_one_shot(vcpu, timer1);
|
||||
stimer_test_auto_enable_one_shot(vcpu, timer2);
|
||||
stimer_test_auto_enable_periodic(vcpu, timer1);
|
||||
stimer_test_one_shot_busy(vcpu, timer1);
|
||||
|
||||
irq_disable();
|
||||
cpu_comp();
|
||||
}
|
||||
|
||||
static void stimer_test_cleanup(void *ctx)
|
||||
{
|
||||
int vcpu = smp_id();
|
||||
|
||||
stimers_shutdown();
|
||||
synic_sint_destroy(vcpu, SINT1_NUM);
|
||||
synic_sint_destroy(vcpu, SINT2_NUM);
|
||||
synic_sint_destroy(SINT1_NUM);
|
||||
synic_sint_destroy(SINT2_NUM);
|
||||
synic_disable();
|
||||
cpu_comp();
|
||||
}
|
||||
|
||||
static void on_each_cpu_async_wait(void (*func)(void *ctx), void *ctx)
|
||||
{
|
||||
int i;
|
||||
|
||||
atomic_set(&g_cpus_comp_count, 0);
|
||||
for (i = 0; i < g_cpus_count; i++) {
|
||||
on_cpu_async(i, func, ctx);
|
||||
}
|
||||
while (atomic_read(&g_cpus_comp_count) != g_cpus_count) {
|
||||
pause();
|
||||
}
|
||||
}
|
||||
|
||||
static void stimer_test_all(void)
|
||||
|
|
@ -332,20 +336,17 @@ static void stimer_test_all(void)
|
|||
smp_init();
|
||||
enable_apic();
|
||||
|
||||
ncpus = cpu_count();
|
||||
if (ncpus > MAX_CPUS)
|
||||
report_abort("number cpus exceeds %d", MAX_CPUS);
|
||||
printf("cpus = %d\n", ncpus);
|
||||
|
||||
handle_irq(SINT1_VEC, stimer_isr);
|
||||
handle_irq(SINT2_VEC, stimer_isr_auto_eoi);
|
||||
|
||||
ncpus = cpu_count();
|
||||
if (ncpus > MAX_CPUS) {
|
||||
ncpus = MAX_CPUS;
|
||||
}
|
||||
|
||||
printf("cpus = %d\n", ncpus);
|
||||
g_cpus_count = ncpus;
|
||||
|
||||
on_each_cpu_async_wait(stimer_test_prepare, (void *)read_cr3());
|
||||
on_each_cpu_async_wait(stimer_test, NULL);
|
||||
on_each_cpu_async_wait(stimer_test_cleanup, NULL);
|
||||
on_cpus(stimer_test_prepare, (void *)read_cr3());
|
||||
on_cpus(stimer_test, NULL);
|
||||
on_cpus(stimer_test_cleanup, NULL);
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
#define MAX_CPUS 4
|
||||
|
||||
static atomic_t isr_enter_count[MAX_CPUS];
|
||||
static atomic_t cpus_comp_count;
|
||||
|
||||
static void synic_sint_auto_eoi_isr(isr_regs_t *regs)
|
||||
{
|
||||
|
|
@ -69,7 +68,7 @@ static void synic_sints_prepare(int vcpu)
|
|||
for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) {
|
||||
vec = sint_vecs[i].vec;
|
||||
auto_eoi = sint_vecs[i].auto_eoi;
|
||||
synic_sint_create(vcpu, i, vec, auto_eoi);
|
||||
synic_sint_create(i, vec, auto_eoi);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -90,8 +89,8 @@ static void synic_test_prepare(void *ctx)
|
|||
}
|
||||
r = rdmsr(HV_X64_MSR_EOM);
|
||||
if (r != 0) {
|
||||
report("Hyper-V SynIC test, EOM read 0x%llx", false, r);
|
||||
goto ret;
|
||||
report("Hyper-V SynIC test, EOM read %#" PRIx64, false, r);
|
||||
return;
|
||||
}
|
||||
|
||||
wrmsr(HV_X64_MSR_SIMP, (u64)virt_to_phys(alloc_page()) |
|
||||
|
|
@ -101,8 +100,6 @@ static void synic_test_prepare(void *ctx)
|
|||
wrmsr(HV_X64_MSR_SCONTROL, HV_SYNIC_CONTROL_ENABLE);
|
||||
|
||||
synic_sints_prepare(smp_id());
|
||||
ret:
|
||||
atomic_inc(&cpus_comp_count);
|
||||
}
|
||||
|
||||
static void synic_sints_test(int dst_vcpu)
|
||||
|
|
@ -125,24 +122,20 @@ static void synic_test(void *ctx)
|
|||
|
||||
irq_enable();
|
||||
synic_sints_test(dst_vcpu);
|
||||
atomic_inc(&cpus_comp_count);
|
||||
}
|
||||
|
||||
static void synic_test_cleanup(void *ctx)
|
||||
{
|
||||
int vcpu = smp_id();
|
||||
int i;
|
||||
|
||||
irq_enable();
|
||||
for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) {
|
||||
synic_sint_destroy(vcpu, i);
|
||||
wrmsr(HV_X64_MSR_SINT0 + i, 0xFF|HV_SYNIC_SINT_MASKED);
|
||||
synic_sint_destroy(i);
|
||||
}
|
||||
|
||||
wrmsr(HV_X64_MSR_SCONTROL, 0);
|
||||
wrmsr(HV_X64_MSR_SIMP, 0);
|
||||
wrmsr(HV_X64_MSR_SIEFP, 0);
|
||||
atomic_inc(&cpus_comp_count);
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
|
|
@ -156,40 +149,25 @@ int main(int ac, char **av)
|
|||
smp_init();
|
||||
enable_apic();
|
||||
|
||||
synic_prepare_sint_vecs();
|
||||
|
||||
ncpus = cpu_count();
|
||||
if (ncpus > MAX_CPUS) {
|
||||
ncpus = MAX_CPUS;
|
||||
}
|
||||
if (ncpus > MAX_CPUS)
|
||||
report_abort("number cpus exceeds %d", MAX_CPUS);
|
||||
printf("ncpus = %d\n", ncpus);
|
||||
|
||||
atomic_set(&cpus_comp_count, 0);
|
||||
for (i = 0; i < ncpus; i++) {
|
||||
on_cpu_async(i, synic_test_prepare, (void *)read_cr3());
|
||||
}
|
||||
printf("prepare\n");
|
||||
while (atomic_read(&cpus_comp_count) != ncpus) {
|
||||
pause();
|
||||
}
|
||||
synic_prepare_sint_vecs();
|
||||
|
||||
printf("prepare\n");
|
||||
on_cpus(synic_test_prepare, (void *)read_cr3());
|
||||
|
||||
atomic_set(&cpus_comp_count, 0);
|
||||
for (i = 0; i < ncpus; i++) {
|
||||
printf("test %d -> %d\n", i, ncpus - 1 - i);
|
||||
on_cpu_async(i, synic_test, (void *)(ulong)(ncpus - 1 - i));
|
||||
}
|
||||
while (atomic_read(&cpus_comp_count) != ncpus) {
|
||||
while (cpus_active() > 1)
|
||||
pause();
|
||||
}
|
||||
|
||||
atomic_set(&cpus_comp_count, 0);
|
||||
for (i = 0; i < ncpus; i++) {
|
||||
on_cpu_async(i, synic_test_cleanup, NULL);
|
||||
}
|
||||
printf("cleanup\n");
|
||||
while (atomic_read(&cpus_comp_count) != ncpus) {
|
||||
pause();
|
||||
}
|
||||
on_cpus(synic_test_cleanup, NULL);
|
||||
|
||||
ok = true;
|
||||
for (i = 0; i < ncpus; ++i) {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ struct test_info {
|
|||
u64 stalls; /* stall count */
|
||||
long long worst; /* worst warp */
|
||||
volatile cycle_t last; /* last cycle seen by test */
|
||||
atomic_t ncpus; /* number of cpu in the test*/
|
||||
int check; /* check cycle ? */
|
||||
};
|
||||
|
||||
|
|
@ -78,29 +77,20 @@ static void kvm_clock_test(void *data)
|
|||
if (!((unsigned long)i & 31))
|
||||
asm volatile("rep; nop");
|
||||
}
|
||||
|
||||
atomic_dec(&hv_test_info->ncpus);
|
||||
}
|
||||
|
||||
static int cycle_test(int ncpus, int check, struct test_info *ti)
|
||||
static int cycle_test(int check, struct test_info *ti)
|
||||
{
|
||||
int i;
|
||||
unsigned long long begin, end;
|
||||
|
||||
begin = rdtsc();
|
||||
|
||||
atomic_set(&ti->ncpus, ncpus);
|
||||
ti->check = check;
|
||||
for (i = ncpus - 1; i >= 0; i--)
|
||||
on_cpu_async(i, kvm_clock_test, (void *)ti);
|
||||
|
||||
/* Wait for the end of other vcpu */
|
||||
while(atomic_read(&ti->ncpus))
|
||||
;
|
||||
on_cpus(kvm_clock_test, ti);
|
||||
|
||||
end = rdtsc();
|
||||
|
||||
printf("Total vcpus: %d\n", ncpus);
|
||||
printf("Total vcpus: %d\n", cpu_count());
|
||||
printf("Test loops: %ld\n", loops);
|
||||
if (check == 1) {
|
||||
printf("Total warps: %" PRId64 "\n", ti->warps);
|
||||
|
|
@ -129,9 +119,9 @@ int main(int ac, char **av)
|
|||
|
||||
ncpus = cpu_count();
|
||||
if (ncpus > MAX_CPU)
|
||||
ncpus = MAX_CPU;
|
||||
for (i = 0; i < ncpus; ++i)
|
||||
on_cpu(i, kvm_clock_init, (void *)0);
|
||||
report_abort("number cpus exceeds %d", MAX_CPU);
|
||||
|
||||
on_cpus(kvm_clock_init, NULL);
|
||||
|
||||
if (ac > 2) {
|
||||
printf("Wallclock test, threshold %ld\n", threshold);
|
||||
|
|
@ -143,26 +133,25 @@ int main(int ac, char **av)
|
|||
printf("Check the stability of raw cycle ...\n");
|
||||
pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT
|
||||
| PVCLOCK_RAW_CYCLE_BIT);
|
||||
if (cycle_test(ncpus, 1, &ti[0]))
|
||||
if (cycle_test(1, &ti[0]))
|
||||
printf("Raw cycle is not stable\n");
|
||||
else
|
||||
printf("Raw cycle is stable\n");
|
||||
|
||||
pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
|
||||
printf("Monotonic cycle test:\n");
|
||||
nerr += cycle_test(ncpus, 1, &ti[1]);
|
||||
nerr += cycle_test(1, &ti[1]);
|
||||
|
||||
printf("Measure the performance of raw cycle ...\n");
|
||||
pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT
|
||||
| PVCLOCK_RAW_CYCLE_BIT);
|
||||
cycle_test(ncpus, 0, &ti[2]);
|
||||
cycle_test(0, &ti[2]);
|
||||
|
||||
printf("Measure the performance of adjusted cycle ...\n");
|
||||
pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
|
||||
cycle_test(ncpus, 0, &ti[3]);
|
||||
cycle_test(0, &ti[3]);
|
||||
|
||||
for (i = 0; i < ncpus; ++i)
|
||||
on_cpu(i, kvm_clock_clear, (void *)0);
|
||||
on_cpus(kvm_clock_clear, NULL);
|
||||
|
||||
return nerr > 0 ? 1 : 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
struct msr_info {
|
||||
int index;
|
||||
char *name;
|
||||
const char *name;
|
||||
struct tc {
|
||||
int valid;
|
||||
unsigned long long value;
|
||||
|
|
@ -78,37 +78,20 @@ static void test_msr_rw(int msr_index, unsigned long long input, unsigned long l
|
|||
{
|
||||
unsigned long long r = 0;
|
||||
int index;
|
||||
char *sptr;
|
||||
const char *sptr;
|
||||
if ((index = find_msr_info(msr_index)) != -1) {
|
||||
sptr = msr_info[index].name;
|
||||
} else {
|
||||
printf("couldn't find name for msr # 0x%x, skipping\n", msr_index);
|
||||
printf("couldn't find name for msr # %#x, skipping\n", msr_index);
|
||||
return;
|
||||
}
|
||||
wrmsr(msr_index, input);
|
||||
r = rdmsr(msr_index);
|
||||
if (expected != r) {
|
||||
printf("testing %s: output = 0x%x:0x%x expected = 0x%x:0x%x\n", sptr,
|
||||
printf("testing %s: output = %#x:%#x expected = %#x:%#x\n", sptr,
|
||||
(u32)(r >> 32), (u32)r, (u32)(expected >> 32), (u32)expected);
|
||||
}
|
||||
report(sptr, expected == r);
|
||||
}
|
||||
|
||||
static void test_syscall_lazy_load(void)
|
||||
{
|
||||
#ifdef __x86_64__
|
||||
extern void syscall_target();
|
||||
u16 cs = read_cs(), ss = read_ss();
|
||||
ulong tmp;
|
||||
|
||||
wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_SCE);
|
||||
wrmsr(MSR_LSTAR, (ulong)syscall_target);
|
||||
wrmsr(MSR_STAR, (uint64_t)cs << 32);
|
||||
asm volatile("pushf; syscall; syscall_target: popf" : "=c"(tmp) : : "r11");
|
||||
write_ss(ss);
|
||||
// will crash horribly if broken
|
||||
report("MSR_*STAR eager loading", true);
|
||||
#endif
|
||||
report("%s", expected == r, sptr);
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
|
|
@ -124,8 +107,6 @@ int main(int ac, char **av)
|
|||
}
|
||||
}
|
||||
|
||||
test_syscall_lazy_load();
|
||||
|
||||
return report_summary();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ union cpuid10_edx {
|
|||
} edx;
|
||||
|
||||
struct pmu_event {
|
||||
char *name;
|
||||
const char *name;
|
||||
uint32_t unit_sel;
|
||||
int min;
|
||||
int max;
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
[ -z "$STANDALONE" ] && source scripts/arch-run.bash
|
||||
|
||||
qemubinarysearch="${QEMU:-qemu-kvm qemu-system-x86_64}"
|
||||
|
||||
for qemucmd in ${qemubinarysearch}
|
||||
do
|
||||
unset QEMUFOUND
|
||||
unset qemu
|
||||
if ! [ -z "${QEMUFOUND=$(${qemucmd} --help 2>/dev/null | grep "QEMU")}" ] &&
|
||||
${qemucmd} -device '?' 2>&1 | grep -F -e \"testdev\" -e \"pc-testdev\" > /dev/null;
|
||||
then
|
||||
qemu="${qemucmd}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "${QEMUFOUND}" ]
|
||||
then
|
||||
echo "A QEMU binary was not found, You can set a custom location by using the QEMU=<path> environment variable "
|
||||
exit 2
|
||||
elif [ -z "${qemu}" ]
|
||||
then
|
||||
echo "No Qemu test device support found"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if
|
||||
${qemu} -device '?' 2>&1 | grep -F "pci-testdev" > /dev/null;
|
||||
then
|
||||
pci_testdev="-device pci-testdev"
|
||||
else
|
||||
pci_testdev=""
|
||||
fi
|
||||
|
||||
if
|
||||
${qemu} -device '?' 2>&1 | grep -F "pc-testdev" > /dev/null;
|
||||
then
|
||||
pc_testdev="-device pc-testdev -device isa-debug-exit,iobase=0xf4,iosize=0x4"
|
||||
else
|
||||
pc_testdev="-device testdev,chardev=testlog -chardev file,id=testlog,path=msr.out"
|
||||
fi
|
||||
|
||||
command="${qemu} -nodefaults -enable-kvm $pc_testdev -vnc none -serial stdio $pci_testdev $hyperv_testdev"
|
||||
[ -f "$ENV" ] && command+=" -initrd $ENV"
|
||||
command+=" -kernel"
|
||||
command="$(timeout_cmd) $command"
|
||||
echo ${command} "$@"
|
||||
|
||||
run_qemu ${command} "$@"
|
||||
|
|
@ -23,7 +23,7 @@ void test_rdtscp(u64 aux)
|
|||
|
||||
wrmsr(MSR_TSC_AUX, aux);
|
||||
rdtscp(&ecx);
|
||||
report("Test RDTSCP %d", ecx == aux, aux);
|
||||
report("Test RDTSCP %" PRIu64, ecx == aux, aux);
|
||||
}
|
||||
|
||||
int main()
|
||||
|
|
|
|||
|
|
@ -1,226 +0,0 @@
|
|||
##############################################################################
|
||||
# unittest configuration
|
||||
#
|
||||
# [unittest_name]
|
||||
# file = <name>.flat # Name of the flat file to be used.
|
||||
# smp = <num> # Number of processors the VM will use
|
||||
# # during this test. Use $MAX_SMP to use
|
||||
# # the maximum the host supports. Defaults
|
||||
# # to one.
|
||||
# extra_params = -append <params...> # Additional parameters used.
|
||||
# arch = i386|x86_64 # Select one if the test case is
|
||||
# # specific to only one.
|
||||
# groups = <group_name1> <group_name2> ... # Used to identify test cases
|
||||
# # with run_tests -g ...
|
||||
# # Specify group_name=nodefault
|
||||
# # to have test not run by
|
||||
# # default
|
||||
# accel = kvm|tcg # Optionally specify if test must run with
|
||||
# # kvm or tcg. If not specified, then kvm will
|
||||
# # be used when available.
|
||||
# timeout = <duration> # Optionally specify a timeout.
|
||||
# check = <path>=<value> # check a file for a particular value before running
|
||||
# # a test. The check line can contain multiple files
|
||||
# # to check separated by a space but each check
|
||||
# # parameter needs to be of the form <path>=<value>
|
||||
##############################################################################
|
||||
|
||||
[apic-split]
|
||||
file = apic.flat
|
||||
smp = 2
|
||||
extra_params = -cpu qemu64,+x2apic,+tsc-deadline -machine kernel_irqchip=split
|
||||
arch = x86_64
|
||||
|
||||
[ioapic-split]
|
||||
file = ioapic.flat
|
||||
extra_params = -cpu qemu64 -machine kernel_irqchip=split
|
||||
arch = x86_64
|
||||
|
||||
[apic]
|
||||
file = apic.flat
|
||||
smp = 2
|
||||
extra_params = -cpu qemu64,+x2apic,+tsc-deadline
|
||||
arch = x86_64
|
||||
timeout = 30
|
||||
|
||||
[ioapic]
|
||||
file = ioapic.flat
|
||||
extra_params = -cpu qemu64
|
||||
arch = x86_64
|
||||
|
||||
[smptest]
|
||||
file = smptest.flat
|
||||
smp = 2
|
||||
|
||||
[smptest3]
|
||||
file = smptest.flat
|
||||
smp = 3
|
||||
|
||||
[vmexit_cpuid]
|
||||
file = vmexit.flat
|
||||
extra_params = -append 'cpuid'
|
||||
groups = vmexit
|
||||
|
||||
[vmexit_vmcall]
|
||||
file = vmexit.flat
|
||||
extra_params = -append 'vmcall'
|
||||
groups = vmexit
|
||||
|
||||
[vmexit_mov_from_cr8]
|
||||
file = vmexit.flat
|
||||
extra_params = -append 'mov_from_cr8'
|
||||
groups = vmexit
|
||||
|
||||
[vmexit_mov_to_cr8]
|
||||
file = vmexit.flat
|
||||
extra_params = -append 'mov_to_cr8'
|
||||
groups = vmexit
|
||||
|
||||
[vmexit_inl_pmtimer]
|
||||
file = vmexit.flat
|
||||
extra_params = -append 'inl_from_pmtimer'
|
||||
groups = vmexit
|
||||
|
||||
[vmexit_ipi]
|
||||
file = vmexit.flat
|
||||
smp = 2
|
||||
extra_params = -append 'ipi'
|
||||
groups = vmexit
|
||||
|
||||
[vmexit_ipi_halt]
|
||||
file = vmexit.flat
|
||||
smp = 2
|
||||
extra_params = -append 'ipi_halt'
|
||||
groups = vmexit
|
||||
|
||||
[vmexit_ple_round_robin]
|
||||
file = vmexit.flat
|
||||
extra_params = -append 'ple_round_robin'
|
||||
groups = vmexit
|
||||
|
||||
[access]
|
||||
file = access.flat
|
||||
arch = x86_64
|
||||
|
||||
[smap]
|
||||
file = smap.flat
|
||||
extra_params = -cpu host
|
||||
|
||||
[pku]
|
||||
file = pku.flat
|
||||
arch = x86_64
|
||||
extra_params = -cpu host
|
||||
|
||||
#[asyncpf]
|
||||
#file = asyncpf.flat
|
||||
|
||||
[emulator]
|
||||
file = emulator.flat
|
||||
arch = x86_64
|
||||
|
||||
[eventinj]
|
||||
file = eventinj.flat
|
||||
|
||||
[hypercall]
|
||||
file = hypercall.flat
|
||||
|
||||
[idt_test]
|
||||
file = idt_test.flat
|
||||
arch = x86_64
|
||||
|
||||
#[init]
|
||||
#file = init.flat
|
||||
|
||||
[msr]
|
||||
file = msr.flat
|
||||
|
||||
[pmu]
|
||||
file = pmu.flat
|
||||
extra_params = -cpu host
|
||||
check = /proc/sys/kernel/nmi_watchdog=0
|
||||
|
||||
[port80]
|
||||
file = port80.flat
|
||||
|
||||
[realmode]
|
||||
file = realmode.flat
|
||||
|
||||
[s3]
|
||||
file = s3.flat
|
||||
|
||||
[sieve]
|
||||
file = sieve.flat
|
||||
|
||||
[tsc]
|
||||
file = tsc.flat
|
||||
extra_params = -cpu kvm64,+rdtscp
|
||||
|
||||
[tsc_adjust]
|
||||
file = tsc_adjust.flat
|
||||
extra_params = -cpu host
|
||||
|
||||
[xsave]
|
||||
file = xsave.flat
|
||||
arch = x86_64
|
||||
extra_params = -cpu host
|
||||
|
||||
[rmap_chain]
|
||||
file = rmap_chain.flat
|
||||
arch = x86_64
|
||||
|
||||
[svm]
|
||||
file = svm.flat
|
||||
smp = 2
|
||||
extra_params = -cpu qemu64,+svm
|
||||
arch = x86_64
|
||||
|
||||
[taskswitch]
|
||||
file = taskswitch.flat
|
||||
arch = i386
|
||||
groups = tasks
|
||||
|
||||
[taskswitch2]
|
||||
file = taskswitch2.flat
|
||||
arch = i386
|
||||
groups = tasks
|
||||
|
||||
[kvmclock_test]
|
||||
file = kvmclock_test.flat
|
||||
smp = 2
|
||||
extra_params = --append "10000000 `date +%s`"
|
||||
|
||||
[pcid]
|
||||
file = pcid.flat
|
||||
extra_params = -cpu qemu64,+pcid
|
||||
arch = x86_64
|
||||
|
||||
[vmx]
|
||||
file = vmx.flat
|
||||
extra_params = -cpu host,+vmx
|
||||
arch = x86_64
|
||||
|
||||
[debug]
|
||||
file = debug.flat
|
||||
arch = x86_64
|
||||
|
||||
[hyperv_synic]
|
||||
file = hyperv_synic.flat
|
||||
smp = 2
|
||||
extra_params = -cpu kvm64,hv_synic -device hyperv-testdev
|
||||
|
||||
[hyperv_stimer]
|
||||
file = hyperv_stimer.flat
|
||||
smp = 2
|
||||
extra_params = -cpu kvm64,hv_time,hv_synic,hv_stimer -device hyperv-testdev
|
||||
|
||||
[hyperv_clock]
|
||||
file = hyperv_clock.flat
|
||||
smp = 2
|
||||
extra_params = -cpu kvm64,hv_time
|
||||
|
||||
[intel_iommu]
|
||||
file = intel-iommu.flat
|
||||
arch = x86_64
|
||||
timeout = 30
|
||||
smp = 4
|
||||
extra_params = -M q35,kernel-irqchip=split -device intel-iommu,intremap=on,eim=off -device edu
|
||||
|
|
@ -387,6 +387,32 @@ static bool pci_io_next(struct test *test)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int has_tscdeadline(void)
|
||||
{
|
||||
uint32_t lvtt;
|
||||
|
||||
if (cpuid(1).c & (1 << 24)) {
|
||||
lvtt = APIC_LVT_TIMER_TSCDEADLINE | IPI_TEST_VECTOR;
|
||||
apic_write(APIC_LVTT, lvtt);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void tscdeadline_immed(void)
|
||||
{
|
||||
wrmsr(MSR_IA32_TSCDEADLINE, rdtsc());
|
||||
asm volatile("nop");
|
||||
}
|
||||
|
||||
static void tscdeadline(void)
|
||||
{
|
||||
x = 0;
|
||||
wrmsr(MSR_IA32_TSCDEADLINE, rdtsc()+3000);
|
||||
while (x == 0) barrier();
|
||||
}
|
||||
|
||||
static struct test tests[] = {
|
||||
{ cpuid_test, "cpuid", .parallel = 1, },
|
||||
{ vmcall, "vmcall", .parallel = 1, },
|
||||
|
|
@ -399,6 +425,8 @@ static struct test tests[] = {
|
|||
{ inl_nop_kernel, "inl_from_kernel", .parallel = 1 },
|
||||
{ outl_elcr_kernel, "outl_to_kernel", .parallel = 1 },
|
||||
{ mov_dr, "mov_dr", .parallel = 1 },
|
||||
{ tscdeadline_immed, "tscdeadline_immed", has_tscdeadline, .parallel = 1, },
|
||||
{ tscdeadline, "tscdeadline", has_tscdeadline, .parallel = 1, },
|
||||
{ self_ipi_sti_nop, "self_ipi_sti_nop", .parallel = 0, },
|
||||
{ self_ipi_sti_hlt, "self_ipi_sti_hlt", .parallel = 0, },
|
||||
{ self_ipi_tpr, "self_ipi_tpr", .parallel = 0, },
|
||||
|
|
@ -419,7 +447,6 @@ static struct test tests[] = {
|
|||
};
|
||||
|
||||
unsigned iterations;
|
||||
static atomic_t nr_cpus_done;
|
||||
|
||||
static void run_test(void *_func)
|
||||
{
|
||||
|
|
@ -428,8 +455,6 @@ static void run_test(void *_func)
|
|||
|
||||
for (i = 0; i < iterations; ++i)
|
||||
func();
|
||||
|
||||
atomic_inc(&nr_cpus_done);
|
||||
}
|
||||
|
||||
static bool do_test(struct test *test)
|
||||
|
|
@ -463,11 +488,7 @@ static bool do_test(struct test *test)
|
|||
for (i = 0; i < iterations; ++i)
|
||||
func();
|
||||
} else {
|
||||
atomic_set(&nr_cpus_done, 0);
|
||||
for (i = cpu_count(); i > 0; i--)
|
||||
on_cpu_async(i-1, run_test, func);
|
||||
while (atomic_read(&nr_cpus_done) < cpu_count())
|
||||
;
|
||||
on_cpus(run_test, func);
|
||||
}
|
||||
t2 = rdtsc();
|
||||
} while ((t2 - t1) < GOAL);
|
||||
|
|
@ -509,8 +530,7 @@ int main(int ac, char **av)
|
|||
nr_cpus = cpu_count();
|
||||
|
||||
irq_enable();
|
||||
for (i = cpu_count(); i > 0; i--)
|
||||
on_cpu(i-1, enable_nx, 0);
|
||||
on_cpus(enable_nx, NULL);
|
||||
|
||||
fadt = find_acpi_table_addr(FACP_SIGNATURE);
|
||||
pm_tmr_blk = fadt->pm_tmr_blk;
|
||||
|
|
@ -524,7 +544,7 @@ int main(int ac, char **av)
|
|||
membar = pcidev.resource[PCI_TESTDEV_BAR_MEM];
|
||||
pci_test.memaddr = ioremap(membar, PAGE_SIZE);
|
||||
pci_test.iobar = pcidev.resource[PCI_TESTDEV_BAR_IO];
|
||||
printf("pci-testdev at 0x%x membar %lx iobar %x\n",
|
||||
printf("pci-testdev at %#x membar %lx iobar %x\n",
|
||||
pcidev.bdf, membar, pci_test.iobar);
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -5,6 +5,7 @@
|
|||
#include "processor.h"
|
||||
#include "bitops.h"
|
||||
#include "asm/page.h"
|
||||
#include "asm/io.h"
|
||||
|
||||
struct vmcs {
|
||||
u32 revision_id; /* vmcs revision identifier */
|
||||
|
|
@ -13,6 +14,11 @@ struct vmcs {
|
|||
char data[0];
|
||||
};
|
||||
|
||||
struct invvpid_operand {
|
||||
u64 vpid;
|
||||
u64 gla;
|
||||
};
|
||||
|
||||
struct regs {
|
||||
u64 rax;
|
||||
u64 rcx;
|
||||
|
|
@ -54,6 +60,8 @@ struct vmx_test {
|
|||
int (*entry_failure_handler)(struct vmentry_failure *failure);
|
||||
struct vmcs *vmcs;
|
||||
int exits;
|
||||
/* Alternative test interface. */
|
||||
void (*v2)(void);
|
||||
};
|
||||
|
||||
union vmx_basic {
|
||||
|
|
@ -108,6 +116,7 @@ enum Encoding {
|
|||
GUEST_SEL_LDTR = 0x080cul,
|
||||
GUEST_SEL_TR = 0x080eul,
|
||||
GUEST_INT_STATUS = 0x0810ul,
|
||||
GUEST_PML_INDEX = 0x0812ul,
|
||||
|
||||
/* 16-Bit Host State Fields */
|
||||
HOST_SEL_ES = 0x0c00ul,
|
||||
|
|
@ -132,6 +141,9 @@ enum Encoding {
|
|||
APIC_ACCS_ADDR = 0x2014ul,
|
||||
EPTP = 0x201aul,
|
||||
EPTP_HI = 0x201bul,
|
||||
PMLADDR = 0x200eul,
|
||||
PMLADDR_HI = 0x200ful,
|
||||
|
||||
|
||||
/* 64-Bit Readonly Data Field */
|
||||
INFO_PHYS_ADDR = 0x2400ul,
|
||||
|
|
@ -317,7 +329,15 @@ enum Reason {
|
|||
VMX_PREEMPT = 52,
|
||||
VMX_INVVPID = 53,
|
||||
VMX_WBINVD = 54,
|
||||
VMX_XSETBV = 55
|
||||
VMX_XSETBV = 55,
|
||||
VMX_APIC_WRITE = 56,
|
||||
VMX_RDRAND = 57,
|
||||
VMX_INVPCID = 58,
|
||||
VMX_VMFUNC = 59,
|
||||
VMX_RDSEED = 61,
|
||||
VMX_PML_FULL = 62,
|
||||
VMX_XSAVES = 63,
|
||||
VMX_XRSTORS = 64,
|
||||
};
|
||||
|
||||
enum Ctrl_exi {
|
||||
|
|
@ -375,6 +395,7 @@ enum Ctrl1 {
|
|||
CPU_URG = 1ul << 7,
|
||||
CPU_WBINVD = 1ul << 6,
|
||||
CPU_RDRAND = 1ul << 11,
|
||||
CPU_PML = 1ul << 17,
|
||||
};
|
||||
|
||||
enum Intr_type {
|
||||
|
|
@ -396,6 +417,37 @@ enum Intr_type {
|
|||
|
||||
#define INTR_INFO_INTR_TYPE_SHIFT 8
|
||||
|
||||
/*
|
||||
* VM-instruction error numbers
|
||||
*/
|
||||
enum vm_instruction_error_number {
|
||||
VMXERR_VMCALL_IN_VMX_ROOT_OPERATION = 1,
|
||||
VMXERR_VMCLEAR_INVALID_ADDRESS = 2,
|
||||
VMXERR_VMCLEAR_VMXON_POINTER = 3,
|
||||
VMXERR_VMLAUNCH_NONCLEAR_VMCS = 4,
|
||||
VMXERR_VMRESUME_NONLAUNCHED_VMCS = 5,
|
||||
VMXERR_VMRESUME_AFTER_VMXOFF = 6,
|
||||
VMXERR_ENTRY_INVALID_CONTROL_FIELD = 7,
|
||||
VMXERR_ENTRY_INVALID_HOST_STATE_FIELD = 8,
|
||||
VMXERR_VMPTRLD_INVALID_ADDRESS = 9,
|
||||
VMXERR_VMPTRLD_VMXON_POINTER = 10,
|
||||
VMXERR_VMPTRLD_INCORRECT_VMCS_REVISION_ID = 11,
|
||||
VMXERR_UNSUPPORTED_VMCS_COMPONENT = 12,
|
||||
VMXERR_VMWRITE_READ_ONLY_VMCS_COMPONENT = 13,
|
||||
VMXERR_VMXON_IN_VMX_ROOT_OPERATION = 15,
|
||||
VMXERR_ENTRY_INVALID_EXECUTIVE_VMCS_POINTER = 16,
|
||||
VMXERR_ENTRY_NONLAUNCHED_EXECUTIVE_VMCS = 17,
|
||||
VMXERR_ENTRY_EXECUTIVE_VMCS_POINTER_NOT_VMXON_POINTER = 18,
|
||||
VMXERR_VMCALL_NONCLEAR_VMCS = 19,
|
||||
VMXERR_VMCALL_INVALID_VM_EXIT_CONTROL_FIELDS = 20,
|
||||
VMXERR_VMCALL_INCORRECT_MSEG_REVISION_ID = 22,
|
||||
VMXERR_VMXOFF_UNDER_DUAL_MONITOR_TREATMENT_OF_SMIS_AND_SMM = 23,
|
||||
VMXERR_VMCALL_INVALID_SMM_MONITOR_FEATURES = 24,
|
||||
VMXERR_ENTRY_INVALID_VM_EXECUTION_CONTROL_FIELDS_IN_EXECUTIVE_VMCS = 25,
|
||||
VMXERR_ENTRY_EVENTS_BLOCKED_BY_MOV_SS = 26,
|
||||
VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID = 28,
|
||||
};
|
||||
|
||||
#define SAVE_GPR \
|
||||
"xchg %rax, regs\n\t" \
|
||||
"xchg %rbx, regs+0x8\n\t" \
|
||||
|
|
@ -451,10 +503,14 @@ enum Intr_type {
|
|||
#define VMX_TEST_VMEXIT 1
|
||||
#define VMX_TEST_EXIT 2
|
||||
#define VMX_TEST_RESUME 3
|
||||
#define VMX_TEST_VMABORT 4
|
||||
#define VMX_TEST_VMSKIP 5
|
||||
|
||||
#define HYPERCALL_BIT (1ul << 12)
|
||||
#define HYPERCALL_MASK 0xFFF
|
||||
#define HYPERCALL_VMEXIT 0x1
|
||||
#define HYPERCALL_VMABORT 0x2
|
||||
#define HYPERCALL_VMSKIP 0x3
|
||||
|
||||
#define EPTP_PG_WALK_LEN_SHIFT 3ul
|
||||
#define EPTP_AD_FLAG (1ul << 6)
|
||||
|
|
@ -487,8 +543,10 @@ enum Intr_type {
|
|||
#define EPT_CAP_INVEPT_ALL (1ull << 26)
|
||||
#define EPT_CAP_AD_FLAG (1ull << 21)
|
||||
#define VPID_CAP_INVVPID (1ull << 32)
|
||||
#define VPID_CAP_INVVPID_SINGLE (1ull << 41)
|
||||
#define VPID_CAP_INVVPID_ALL (1ull << 42)
|
||||
#define VPID_CAP_INVVPID_ADDR (1ull << 40)
|
||||
#define VPID_CAP_INVVPID_CXTGLB (1ull << 41)
|
||||
#define VPID_CAP_INVVPID_ALL (1ull << 42)
|
||||
#define VPID_CAP_INVVPID_CXTLOC (1ull << 43)
|
||||
|
||||
#define PAGE_SIZE_2M (512 * PAGE_SIZE)
|
||||
#define PAGE_SIZE_1G (512 * PAGE_SIZE_2M)
|
||||
|
|
@ -506,19 +564,23 @@ enum Intr_type {
|
|||
#define EPT_VLT_PERM_RD (1 << 3)
|
||||
#define EPT_VLT_PERM_WR (1 << 4)
|
||||
#define EPT_VLT_PERM_EX (1 << 5)
|
||||
#define EPT_VLT_PERMS (EPT_VLT_PERM_RD | EPT_VLT_PERM_WR | \
|
||||
EPT_VLT_PERM_EX)
|
||||
#define EPT_VLT_LADDR_VLD (1 << 7)
|
||||
#define EPT_VLT_PADDR (1 << 8)
|
||||
|
||||
#define MAGIC_VAL_1 0x12345678ul
|
||||
#define MAGIC_VAL_2 0x87654321ul
|
||||
#define MAGIC_VAL_3 0xfffffffful
|
||||
#define MAGIC_VAL_4 0xdeadbeeful
|
||||
|
||||
#define INVEPT_SINGLE 1
|
||||
#define INVEPT_GLOBAL 2
|
||||
|
||||
#define INVVPID_SINGLE_ADDRESS 0
|
||||
#define INVVPID_SINGLE 1
|
||||
#define INVVPID_ADDR 0
|
||||
#define INVVPID_CONTEXT_GLOBAL 1
|
||||
#define INVVPID_ALL 2
|
||||
#define INVVPID_CONTEXT_LOCAL 3
|
||||
|
||||
#define ACTV_ACTIVE 0
|
||||
#define ACTV_HLT 1
|
||||
|
|
@ -532,10 +594,41 @@ extern union vmx_ctrl_msr ctrl_exit_rev;
|
|||
extern union vmx_ctrl_msr ctrl_enter_rev;
|
||||
extern union vmx_ept_vpid ept_vpid;
|
||||
|
||||
extern u64 *vmxon_region;
|
||||
|
||||
void vmx_set_test_stage(u32 s);
|
||||
u32 vmx_get_test_stage(void);
|
||||
void vmx_inc_test_stage(void);
|
||||
|
||||
static int vmx_on(void)
|
||||
{
|
||||
bool ret;
|
||||
u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF;
|
||||
asm volatile ("push %1; popf; vmxon %2; setbe %0\n\t"
|
||||
: "=q" (ret) : "q" (rflags), "m" (vmxon_region) : "cc");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vmx_off(void)
|
||||
{
|
||||
bool ret;
|
||||
u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF;
|
||||
|
||||
asm volatile("push %1; popf; vmxoff; setbe %0\n\t"
|
||||
: "=q"(ret) : "q" (rflags) : "cc");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int make_vmcs_current(struct vmcs *vmcs)
|
||||
{
|
||||
bool ret;
|
||||
u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF;
|
||||
|
||||
asm volatile ("push %1; popf; vmptrld %2; setbe %0"
|
||||
: "=q" (ret) : "q" (rflags), "m" (vmcs) : "cc");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int vmcs_clear(struct vmcs *vmcs)
|
||||
{
|
||||
bool ret;
|
||||
|
|
@ -553,6 +646,25 @@ static inline u64 vmcs_read(enum Encoding enc)
|
|||
return val;
|
||||
}
|
||||
|
||||
static inline int vmcs_read_checking(enum Encoding enc, u64 *value)
|
||||
{
|
||||
u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF;
|
||||
u64 encoding = enc;
|
||||
u64 val;
|
||||
|
||||
asm volatile ("shl $8, %%rax;"
|
||||
"sahf;"
|
||||
"vmread %[encoding], %[val];"
|
||||
"lahf;"
|
||||
"shr $8, %%rax"
|
||||
: /* output */ [val]"=rm"(val), "+a"(rflags)
|
||||
: /* input */ [encoding]"r"(encoding)
|
||||
: /* clobber */ "cc");
|
||||
|
||||
*value = val;
|
||||
return rflags & (X86_EFLAGS_CF | X86_EFLAGS_ZF);
|
||||
}
|
||||
|
||||
static inline int vmcs_write(enum Encoding enc, u64 val)
|
||||
{
|
||||
bool ret;
|
||||
|
|
@ -564,10 +676,12 @@ static inline int vmcs_write(enum Encoding enc, u64 val)
|
|||
static inline int vmcs_save(struct vmcs **vmcs)
|
||||
{
|
||||
bool ret;
|
||||
unsigned long pa;
|
||||
u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF;
|
||||
|
||||
asm volatile ("push %1; popf; vmptrst %2; setbe %0"
|
||||
: "=q" (ret) : "q" (rflags), "m" (*vmcs) : "cc");
|
||||
asm volatile ("push %2; popf; vmptrst %1; setbe %0"
|
||||
: "=q" (ret), "=m" (pa) : "r" (rflags) : "cc");
|
||||
*vmcs = (pa == -1ull) ? NULL : phys_to_virt(pa);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -584,21 +698,18 @@ static inline bool invept(unsigned long type, u64 eptp)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline bool invvpid(unsigned long type, u16 vpid, u64 gva)
|
||||
static inline bool invvpid(unsigned long type, u64 vpid, u64 gla)
|
||||
{
|
||||
bool ret;
|
||||
u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF;
|
||||
|
||||
struct {
|
||||
u64 vpid : 16;
|
||||
u64 rsvd : 48;
|
||||
u64 gva;
|
||||
} operand = {vpid, 0, gva};
|
||||
struct invvpid_operand operand = {vpid, gla};
|
||||
asm volatile("push %1; popf; invvpid %2, %3; setbe %0"
|
||||
: "=q" (ret) : "r" (rflags), "m"(operand),"r"(type) : "cc");
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *exit_reason_description(u64 reason);
|
||||
void print_vmexit_info();
|
||||
void print_vmentry_failure_info(struct vmentry_failure *failure);
|
||||
void ept_sync(int type, u64 eptp);
|
||||
|
|
@ -614,9 +725,83 @@ void install_ept(unsigned long *pml4, unsigned long phys,
|
|||
unsigned long guest_addr, u64 perm);
|
||||
void setup_ept_range(unsigned long *pml4, unsigned long start,
|
||||
unsigned long len, int map_1g, int map_2m, u64 perm);
|
||||
unsigned long get_ept_pte(unsigned long *pml4,
|
||||
unsigned long guest_addr, int level);
|
||||
int set_ept_pte(unsigned long *pml4, unsigned long guest_addr,
|
||||
bool get_ept_pte(unsigned long *pml4, unsigned long guest_addr, int level,
|
||||
unsigned long *pte);
|
||||
void set_ept_pte(unsigned long *pml4, unsigned long guest_addr,
|
||||
int level, u64 pte_val);
|
||||
void check_ept_ad(unsigned long *pml4, u64 guest_cr3,
|
||||
unsigned long guest_addr, int expected_gpa_ad,
|
||||
int expected_pt_ad);
|
||||
void clear_ept_ad(unsigned long *pml4, u64 guest_cr3,
|
||||
unsigned long guest_addr);
|
||||
|
||||
bool ept_2m_supported(void);
|
||||
bool ept_1g_supported(void);
|
||||
bool ept_huge_pages_supported(int level);
|
||||
bool ept_execute_only_supported(void);
|
||||
bool ept_ad_bits_supported(void);
|
||||
|
||||
void enter_guest(void);
|
||||
|
||||
typedef void (*test_guest_func)(void);
|
||||
typedef void (*test_teardown_func)(void *data);
|
||||
void test_set_guest(test_guest_func func);
|
||||
void test_add_teardown(test_teardown_func func, void *data);
|
||||
void test_skip(const char *msg);
|
||||
|
||||
void __abort_test(void);
|
||||
|
||||
#define TEST_ASSERT(cond) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
report("%s:%d: Assertion failed: %s", 0, \
|
||||
__FILE__, __LINE__, #cond); \
|
||||
dump_stack(); \
|
||||
__abort_test(); \
|
||||
} \
|
||||
report_pass(); \
|
||||
} while (0)
|
||||
|
||||
#define TEST_ASSERT_MSG(cond, fmt, args...) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
report("%s:%d: Assertion failed: %s\n" fmt, 0, \
|
||||
__FILE__, __LINE__, #cond, ##args); \
|
||||
dump_stack(); \
|
||||
__abort_test(); \
|
||||
} \
|
||||
report_pass(); \
|
||||
} while (0)
|
||||
|
||||
#define __TEST_EQ(a, b, a_str, b_str, assertion, fmt, args...) \
|
||||
do { \
|
||||
typeof(a) _a = a; \
|
||||
typeof(b) _b = b; \
|
||||
if (_a != _b) { \
|
||||
char _bin_a[BINSTR_SZ]; \
|
||||
char _bin_b[BINSTR_SZ]; \
|
||||
binstr(_a, _bin_a); \
|
||||
binstr(_b, _bin_b); \
|
||||
report("%s:%d: %s failed: (%s) == (%s)\n" \
|
||||
"\tLHS: %#018lx - %s - %lu\n" \
|
||||
"\tRHS: %#018lx - %s - %lu%s" fmt, 0, \
|
||||
__FILE__, __LINE__, \
|
||||
assertion ? "Assertion" : "Expectation", a_str, b_str, \
|
||||
(unsigned long) _a, _bin_a, (unsigned long) _a, \
|
||||
(unsigned long) _b, _bin_b, (unsigned long) _b, \
|
||||
fmt[0] == '\0' ? "" : "\n", ## args); \
|
||||
dump_stack(); \
|
||||
if (assertion) \
|
||||
__abort_test(); \
|
||||
} \
|
||||
report_pass(); \
|
||||
} while (0)
|
||||
|
||||
#define TEST_ASSERT_EQ(a, b) __TEST_EQ(a, b, #a, #b, 1, "")
|
||||
#define TEST_ASSERT_EQ_MSG(a, b, fmt, args...) \
|
||||
__TEST_EQ(a, b, #a, #b, 1, fmt, ## args)
|
||||
#define TEST_EXPECT_EQ(a, b) __TEST_EQ(a, b, #a, #b, 0, "")
|
||||
#define TEST_EXPECT_EQ_MSG(a, b, fmt, args...) \
|
||||
__TEST_EQ(a, b, #a, #b, 0, fmt, ## args)
|
||||
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -75,7 +75,7 @@ void test_xsave(void)
|
|||
printf("Legal instruction testing:\n");
|
||||
|
||||
supported_xcr0 = get_supported_xcr0();
|
||||
printf("Supported XCR0 bits: 0x%lx\n", supported_xcr0);
|
||||
printf("Supported XCR0 bits: %#lx\n", supported_xcr0);
|
||||
|
||||
test_bits = XSTATE_FP | XSTATE_SSE;
|
||||
report("Check minimal XSAVE required bits",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue