All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] curl: Upgrade 7.50.1.bb -> curl_7.51.0.bb
From: akuster808 @ 2016-11-09 15:16 UTC (permalink / raw)
  To: Sona Sarmadi, Richard Purdie (richard.purdie@linuxfoundation.org)
  Cc: openembedded-core@lists.openembedded.org
In-Reply-To: <3230301C09DEF9499B442BBE162C5E48ABEB644D@SESTOEX04.enea.se>



On 11/09/2016 03:58 AM, Sona Sarmadi wrote:
> Hi guys,
>
> curl 7.51.0-r0 addresses all these CVEs. I wonder if we can upgrade krogoth and morty to curl 7.51.0-r0 as well?
Updating morty seems plausible . I appears the changes are mostly bug fixes.
Krogoth is a large jump and I would not recommend upgrading the package.

- Armin

> Both package versions are using same share library version i.e. libcurl.so.4.4.0 so I assume full ABI compatibility.
>
> tmp/work/i586-poky-linux/curl/7.47.1-r0/sysroot-destdir/usr/lib/libcurl.so.4.4.0
> tmp/work/i586-poky-linux/curl/7.51.0-r0/sysroot-destdir/usr/lib/libcurl.so.4.4.0
>
> For more info see:
> https://bugzilla.yoctoproject.org/show_bug.cgi?id=10617
>
> Thanks
> //Sona
> -----Original Message-----
> From: openembedded-core-bounces@lists.openembedded.org [mailto:openembedded-core-bounces@lists.openembedded.org] On Behalf Of Sona Sarmadi
> Sent: den 8 november 2016 11:42
> To: openembedded-core@lists.openembedded.org
> Subject: [OE-core] [PATCH] curl: Upgrade 7.50.1.bb -> curl_7.51.0.bb
>
> The upgrade addresses following CVEs:
> CVE-2016-8615: cookie injection for other servers
> CVE-2016-8616: case insensitive password comparison
> CVE-2016-8617: OOB write via unchecked multiplication
> CVE-2016-8618: double-free in curl_maprintf
> CVE-2016-8619: double-free in krb5 code
> CVE-2016-8620: glob parser write/read out of bounds
> CVE-2016-8621: curl_getdate read out of bounds
> CVE-2016-8622: URL unescape heap overflow via integer truncation
> CVE-2016-8623: Use-after-free via shared cookies
> CVE-2016-8624: invalid URL parsing with '#'
> CVE-2016-8625: IDNA 2003 makes curl use wrong host
>
> Reference:
> https://curl.haxx.se/docs/security.html
>
> Fixes [Yocto #10617]
>
> Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>
> ---
>   meta/recipes-support/curl/{curl_7.50.1.bb => curl_7.51.0.bb} | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)  rename meta/recipes-support/curl/{curl_7.50.1.bb => curl_7.51.0.bb} (94%)
>
> diff --git a/meta/recipes-support/curl/curl_7.50.1.bb b/meta/recipes-support/curl/curl_7.51.0.bb
> similarity index 94%
> rename from meta/recipes-support/curl/curl_7.50.1.bb
> rename to meta/recipes-support/curl/curl_7.51.0.bb
> index a21419a..e1a996b 100644
> --- a/meta/recipes-support/curl/curl_7.50.1.bb
> +++ b/meta/recipes-support/curl/curl_7.51.0.bb
> @@ -14,8 +14,8 @@ SRC_URI = "http://curl.haxx.se/download/curl-${PV}.tar.bz2 \  #  SRC_URI += " file://configure_ac.patch"
>   
> -SRC_URI[md5sum] = "015f6a0217ca6f2c5442ca406476920b"
> -SRC_URI[sha256sum] = "3c12c5f54ccaa1d40abc65d672107dcc75d3e1fcb38c267484334280096e5156"
> +SRC_URI[md5sum] = "09a7c5769a7eae676d5e2c86d51f167e"
> +SRC_URI[sha256sum] = "7f8240048907e5030f67be0a6129bc4b333783b9cca1391026d700835a788dde"
>   
>   inherit autotools pkgconfig binconfig multilib_header
>   
> --
> 1.9.1
>
> --
> _______________________________________________
> Openembedded-core mailing list
> Openembedded-core@lists.openembedded.org
> http://lists.openembedded.org/mailman/listinfo/openembedded-core



^ permalink raw reply

* Re: [PATCH] drm/i915: Spin until breadcrumb threads are complete
From: Chris Wilson @ 2016-11-09 15:16 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: intel-gfx
In-Reply-To: <674407a0-4c5f-b107-3d00-39c9ce47c1e4@linux.intel.com>

On Wed, Nov 09, 2016 at 02:53:34PM +0000, Tvrtko Ursulin wrote:
> Looks OK. Side note to myself - catch up on the rcu waiter business.
> 
> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

Ta, pushed to have one less wart.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply

* [Qemu-devel] [Bug 1193564] Re: monitor: rename `screendump` command to `screenshot`
From: Thomas Huth @ 2016-11-09 15:04 UTC (permalink / raw)
  To: qemu-devel
In-Reply-To: <20130622071305.4376.72719.malonedeb@gac.canonical.com>

The monitor has TAB completion, so you should get the right command if
you type "screen" + TAB. And since it's been quite a while since this
ticket has been opened and nobody took care of this, I think it's quite
unlikely that the name of the command gets changed, so closing this
ticket now as "Won't fix" - sorry!

** Changed in: qemu
       Status: New => Won't Fix

** Changed in: qemu
   Importance: Undecided => Wishlist

-- 
You received this bug notification because you are a member of qemu-
devel-ml, which is subscribed to QEMU.
https://bugs.launchpad.net/bugs/1193564

Title:
  monitor: rename `screendump` command to `screenshot`

Status in QEMU:
  Won't Fix

Bug description:
  `screendump` is hard to memorize for occasional users. It is easier to
  remember `screenshot` name.

To manage notifications about this bug go to:
https://bugs.launchpad.net/qemu/+bug/1193564/+subscriptions

^ permalink raw reply

* Re: [GIT PULL] kvm/page_track changes for i915 KVMGT
From: Daniel Vetter @ 2016-11-09 15:15 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: linux-kernel, kvm, rkrcmar, intel-gfx, Daniel Wetter, Jike Song,
	Jani Nikula, Zhenyu Wang
In-Reply-To: <1478701519-13533-1-git-send-email-pbonzini@redhat.com>

On Wed, Nov 09, 2016 at 03:25:19PM +0100, Paolo Bonzini wrote:
> Daniel,
> 
> The following changes since commit d9092f52d7e61dd1557f2db2400ddb430e85937e:
> 
>   kvm: x86: Check memopp before dereference (CVE-2016-8630) (2016-11-02 21:31:53 +0100)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/virt/kvm/kvm.git tags/for-kvmgt
> 
> for you to fetch changes up to 871b7ef2a1850d0b435c8b324bf4a5d391adde3f:
> 
>   kvm/page_track: export symbols for external usage (2016-11-04 12:13:20 +0100)

Pulled into drm-intel, thanks. Please also pull this into your kvm-next
tree to make sure we can land kvm/drm trees in any order for the 4.10
merge window.

Thanks, Daniel

> 
> ----------------------------------------------------------------
> The three KVM patches that KVMGT needs.
> 
> ----------------------------------------------------------------
> Jike Song (2):
>       kvm/page_track: call notifiers with kvm_page_track_notifier_node
>       kvm/page_track: export symbols for external usage
> 
> Xiaoguang Chen (1):
>       KVM: x86: add track_flush_slot page track notifier
> 
>  arch/x86/include/asm/kvm_page_track.h | 14 +++++++++++++-
>  arch/x86/kvm/mmu.c                    | 11 ++++++++++-
>  arch/x86/kvm/page_track.c             | 31 ++++++++++++++++++++++++++++++-
>  arch/x86/kvm/x86.c                    |  2 +-
>  4 files changed, 54 insertions(+), 4 deletions(-)

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply

* Re: [GIT PULL] kvm/page_track changes for i915 KVMGT
From: Daniel Vetter @ 2016-11-09 15:15 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: kvm, rkrcmar, Jani Nikula, intel-gfx, linux-kernel
In-Reply-To: <1478701519-13533-1-git-send-email-pbonzini@redhat.com>

On Wed, Nov 09, 2016 at 03:25:19PM +0100, Paolo Bonzini wrote:
> Daniel,
> 
> The following changes since commit d9092f52d7e61dd1557f2db2400ddb430e85937e:
> 
>   kvm: x86: Check memopp before dereference (CVE-2016-8630) (2016-11-02 21:31:53 +0100)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/virt/kvm/kvm.git tags/for-kvmgt
> 
> for you to fetch changes up to 871b7ef2a1850d0b435c8b324bf4a5d391adde3f:
> 
>   kvm/page_track: export symbols for external usage (2016-11-04 12:13:20 +0100)

Pulled into drm-intel, thanks. Please also pull this into your kvm-next
tree to make sure we can land kvm/drm trees in any order for the 4.10
merge window.

Thanks, Daniel

> 
> ----------------------------------------------------------------
> The three KVM patches that KVMGT needs.
> 
> ----------------------------------------------------------------
> Jike Song (2):
>       kvm/page_track: call notifiers with kvm_page_track_notifier_node
>       kvm/page_track: export symbols for external usage
> 
> Xiaoguang Chen (1):
>       KVM: x86: add track_flush_slot page track notifier
> 
>  arch/x86/include/asm/kvm_page_track.h | 14 +++++++++++++-
>  arch/x86/kvm/mmu.c                    | 11 ++++++++++-
>  arch/x86/kvm/page_track.c             | 31 ++++++++++++++++++++++++++++++-
>  arch/x86/kvm/x86.c                    |  2 +-
>  4 files changed, 54 insertions(+), 4 deletions(-)

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply

* Re: [PATCH v2 02/11] acpi: Define ACPI IO registers for PVH guests
From: Boris Ostrovsky @ 2016-11-09 15:14 UTC (permalink / raw)
  To: Andrew Cooper, xen-devel
  Cc: wei.liu2, ian.jackson, Julien Grall, Paul Durrant, jbeulich,
	roger.pau
In-Reply-To: <8b9bbfeb-3bc5-239a-a7da-93cbda43bad8@citrix.com>

On 11/09/2016 09:59 AM, Andrew Cooper wrote:
>
>> diff --git a/xen/include/public/hvm/ioreq.h b/xen/include/public/hvm/ioreq.h
>> index 2e5809b..e3fa704 100644
>> --- a/xen/include/public/hvm/ioreq.h
>> +++ b/xen/include/public/hvm/ioreq.h
>> @@ -24,6 +24,8 @@
>>  #ifndef _IOREQ_H_
>>  #define _IOREQ_H_
>>  
>> +#include "hvm_info_table.h" /* HVM_MAX_VCPUS */
>> +
>>  #define IOREQ_READ      1
>>  #define IOREQ_WRITE     0
>>  
>> @@ -124,6 +126,17 @@ typedef struct buffered_iopage buffered_iopage_t;
>>  #define ACPI_GPE0_BLK_ADDRESS        ACPI_GPE0_BLK_ADDRESS_V0
>>  #define ACPI_GPE0_BLK_LEN            ACPI_GPE0_BLK_LEN_V0
>>  
>> +#define ACPI_PM1A_EVT_BLK_LEN        0x04
>> +#define ACPI_PM1A_CNT_BLK_LEN        0x02
>> +#define ACPI_PM_TMR_BLK_LEN          0x04
>> +
>> +/* Location of online VCPU bitmap. */
>> +#define ACPI_CPU_MAP                 0xaf00
>> +#define ACPI_CPU_MAP_LEN             ((HVM_MAX_VCPUS / 8) + \
>> +                                      ((HVM_MAX_VCPUS & 7) ? 1 : 0))
>> +#if ACPI_CPU_MAP + ACPI_CPU_MAP_LEN >= ACPI_GPE0_BLK_ADDRESS_V1
>> +#error "ACPI_CPU_MAP is too big"
>> +#endif
> Why is this in ioreq.h?  It has nothing to do with ioreq's.
>
> The current ACPI bits in here are to do with the qemu ACPI interface,
> not the Xen ACPI interface.
>
> Also, please can we avoid hard-coding the location of the map in the
> hypervisor ABI.  These constants make it impossible to ever extend the
> number of HVM vcpus at a future date.

The first three logically belong here because corresponding blocks'
addresses are defined right above.

ACPI_CPU_MAP has to be seen by both the toolstack (libacpi) and the
hypervisor (and qemu as well, although it is defined as
PIIX4_CPU_HOTPLUG_IO_BASE).

Where do you think it should go then?

-boris



_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply

* Re: [PATCH] sound: soc-core: make kernel complaints on -EPROBE_DEFER dev_dbg
From: Ladislav Michl @ 2016-11-09 15:14 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, Liam Girdwood
In-Reply-To: <20161109143642.7knvr63vwmcgunjf@sirena.org.uk>

On Wed, Nov 09, 2016 at 02:36:42PM +0000, Mark Brown wrote:
> On Wed, Nov 09, 2016 at 03:00:36PM +0100, Ladislav Michl wrote:
> > There is no point having these complaints to be dev_err as
> > they are just adding noise to bootlog.
> 
> No, errors are errors and not displaying them just makes it harder for
> people to debug things.  If you don't want to see errors just change
> your system configuratiion to hide them.

For sure I want to see all errors, but this is not hardware error nor
kernel misconfiguration, so showing it to the user is a bit pointless.
I'm using quiet boot on production systems and technicians are told
to report all errors they see... This one pops up and has nothing
to do with errorneous behaviour.

> If you don't like deferred probing please contribute to the efforts
> to order probing.

I just tried to make it consistend to other subsystems where patches to
silence deferred probing warnings are accepted...

> Please use subject lines matching the style for the subsystem.  This
> makes it easier for people to identify relevant patches.

I wasn't aware of it, sorry. Will fix it next time.

Best regards,
	ladis

^ permalink raw reply

* Re: [Qemu-devel] [PATCH for-2.8] migration: Fix return code of ram_save_iterate()
From: Dr. David Alan Gilbert @ 2016-11-09 15:13 UTC (permalink / raw)
  To: Thomas Huth; +Cc: Amit Shah, Juan Quintela, qemu-devel, David Gibson
In-Reply-To: <1283dfcc-2f4a-299d-6ecb-16ccd5eff89e@redhat.com>

* Thomas Huth (thuth@redhat.com) wrote:
> On 09.11.2016 08:18, Amit Shah wrote:
> > On (Fri) 04 Nov 2016 [14:10:17], Thomas Huth wrote:
> >> qemu_savevm_state_iterate() expects the iterators to return 1
> >> when they are done, and 0 if there is still something left to do.
> >> However, ram_save_iterate() does not obey this rule and returns
> >> the number of saved pages instead. This causes a fatal hang with
> >> ppc64 guests when you run QEMU like this (also works with TCG):
> > 
> > "works with" -- does that mean reproduces with?
> 
> Yes, that's what I've meant: You can reproduce it with TCG (e.g. running
> on a x86 system), too, there's no need for a real POWER machine with KVM
> here.

How did you trigger it on x86?

Dave

> >>  qemu-img create -f qcow2  /tmp/test.qcow2 1M
> >>  qemu-system-ppc64 -nographic -nodefaults -m 256 \
> >>                    -hda /tmp/test.qcow2 -serial mon:stdio
> >>
> >> ... then switch to the monitor by pressing CTRL-a c and try to
> >> save a snapshot with "savevm test1" for example.
> >>
> >> After the first iteration, ram_save_iterate() always returns 0 here,
> >> so that qemu_savevm_state_iterate() hangs in an endless loop and you
> >> can only "kill -9" the QEMU process.
> >> Fix it by using proper return values in ram_save_iterate().
> >>
> >> Signed-off-by: Thomas Huth <thuth@redhat.com>
> >> ---
> >>  migration/ram.c | 6 +++---
> >>  1 file changed, 3 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/migration/ram.c b/migration/ram.c
> >> index fb9252d..a1c8089 100644
> >> --- a/migration/ram.c
> >> +++ b/migration/ram.c
> >> @@ -1987,7 +1987,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
> >>      int ret;
> >>      int i;
> >>      int64_t t0;
> >> -    int pages_sent = 0;
> >> +    int done = 0;
> >>  
> >>      rcu_read_lock();
> >>      if (ram_list.version != last_version) {
> >> @@ -2007,9 +2007,9 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
> >>          pages = ram_find_and_save_block(f, false, &bytes_transferred);
> >>          /* no more pages to sent */
> >>          if (pages == 0) {
> >> +            done = 1;
> >>              break;
> >>          }
> >> -        pages_sent += pages;
> >>          acct_info.iterations++;
> >>  
> >>          /* we want to check in the 1st loop, just in case it was the 1st time
> >> @@ -2044,7 +2044,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
> >>          return ret;
> >>      }
> >>  
> >> -    return pages_sent;
> >> +    return done;
> >>  }
> > 
> > I agree with David, we can just remove the return value.  The first
> > patch of the series can do that; and this one could become the 2nd
> > patch.  Should be OK for the soft freeze.
> 
> Sorry, I still did not quite get it - if I'd change the return type of
> ram_save_iterate() and the other iterate functions to "void", how is
> qemu_savevm_state_iterate() supposed to know whether all iterators are
> done or not? And other iterators also use negative return values to
> signal errors - should that then be handled via an "Error **" parameter
> instead? ... my gut feeling still says that such a bigger rework (we've
> got to touch all iterators for this!) should rather not be done right in
> the middle of the freeze period...
> 
>  Thomas
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

^ permalink raw reply

* [PATCH v3] drm/i915: Trim the object sg table
From: Tvrtko Ursulin @ 2016-11-09 15:13 UTC (permalink / raw)
  To: Intel-gfx
In-Reply-To: <20161109144436.GB7229@nuc-i3427.alporthouse.com>

From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

At the moment we allocate enough sg table entries assuming we
will not be able to do any coalescing. But since in practice
we most often can, and more so very effectively, this ends up
wasting a lot of memory.

A simple and effective way of trimming the over-allocated
entries is to copy the table over to a new one allocated to the
exact size.

Experiments on my freshly logged and idle desktop (KDE) showed
that by doing this we can save approximately 1 MiB of RAM, or
when running a typical benchmark like gl_manhattan I have
even seen a 6 MiB saving.

More complicated techniques such as only copying the last used
page and freeing the rest are left to the reader.

v2:
 * Update commit message.
 * Use temporary sg_table on stack. (Chris Wilson)

v3:
 * Commit message update.
 * Comment added.
 * Replace memcpy with copy assignment.
   (Chris Wilson)

Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_gem.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index d2ad73d0b5b9..1c20edba7f2a 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2232,6 +2232,30 @@ static unsigned int swiotlb_max_size(void)
 #endif
 }
 
+static void i915_sg_trim(struct sg_table *orig_st)
+{
+	struct sg_table new_st;
+	struct scatterlist *sg, *new_sg;
+	unsigned int i;
+
+	if (orig_st->nents == orig_st->orig_nents)
+		return;
+
+	if (sg_alloc_table(&new_st, orig_st->nents, GFP_KERNEL))
+		return;
+
+	new_sg = new_st.sgl;
+	for_each_sg(orig_st->sgl, sg, orig_st->nents, i) {
+		sg_set_page(new_sg, sg_page(sg), sg->length, 0);
+		/* called before being DMA mapped, no need to copy sg->dma_* */
+		new_sg = sg_next(new_sg);
+	}
+
+	sg_free_table(orig_st);
+
+	*orig_st = new_st;
+}
+
 static struct sg_table *
 i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
 {
@@ -2317,6 +2341,9 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
 	if (sg) /* loop terminated early; short sg table */
 		sg_mark_end(sg);
 
+	/* Trim unused sg entries to avoid wasting memory. */
+	i915_sg_trim(st);
+
 	ret = i915_gem_gtt_prepare_pages(obj, st);
 	if (ret)
 		goto err_pages;
-- 
2.7.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related

* Re: [PATCH] drm/i915: Trim the object sg table
From: Chris Wilson @ 2016-11-09 15:13 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: Intel-gfx
In-Reply-To: <ae095536-0fa5-4c1e-9a08-fcfd46fc9237@linux.intel.com>

On Wed, Nov 09, 2016 at 03:07:38PM +0000, Tvrtko Ursulin wrote:
> 
> On 09/11/2016 14:44, Chris Wilson wrote:
> >Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
> >           ^ I remembered it this time!
> >Took a couple of attempts to spell my name right though.
> 
> Thanks! I assume I can keep it for the above little changes.

Yes.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply

* Re: [Qemu-devel] [PATCH v6 00/19] Remaining MTTCG Base patches and ARM enablement
From: Paolo Bonzini @ 2016-11-09 15:11 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani, nikunj,
	mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana
In-Reply-To: <20161109145748.27282-1-alex.bennee@linaro.org>



On 09/11/2016 15:57, Alex Bennée wrote:
> The one outstanding question is how to deal with the TLB flush
> semantics of the various guest architectures. Currently flushes to
> other vCPUs will happen at the end of their currently executing
> Translation Block which could mean the originating vCPU makes
> assumptions about flushes having been completed when they haven't. In
> practice this hasn't been a problem and I haven't been able to
> construct a test case so far that would fail in such a case. This is
> probably because most tear downs of the other vCPU TLBs tend to be
> done while the other vCPUs are not doing much. If anyone can come up
> with a test case that would fail if this assumption isn't met then
> please let me know.

Have you tried implementing ARM's DMB semantics correctly?

Paolo

^ permalink raw reply

* [PATCH kvm-unit-tests v2 17/17] x86/unittests: add intel-iommu test
From: Peter Xu @ 2016-11-09 15:10 UTC (permalink / raw)
  To: kvm; +Cc: drjones, rkrcmar, peterx, agordeev, jan.kiszka, pbonzini
In-Reply-To: <1478704224-20472-1-git-send-email-peterx@redhat.com>

Signed-off-by: Peter Xu <peterx@redhat.com>
---
 x86/unittests.cfg | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/x86/unittests.cfg b/x86/unittests.cfg
index 23395c6..5413838 100644
--- a/x86/unittests.cfg
+++ b/x86/unittests.cfg
@@ -217,3 +217,10 @@ extra_params = -cpu kvm64,hv_time,hv_synic,hv_stimer -device hyperv-testdev
 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
-- 
2.7.4


^ permalink raw reply related

* [PATCH kvm-unit-tests v2 16/17] x86: intel-iommu: add IR MSI test
From: Peter Xu @ 2016-11-09 15:10 UTC (permalink / raw)
  To: kvm; +Cc: drjones, rkrcmar, peterx, agordeev, jan.kiszka, pbonzini
In-Reply-To: <1478704224-20472-1-git-send-email-peterx@redhat.com>

First of all, vtd_setup_msi() is provided. It setup IRTE entries,
meanwhile, setup PCI device MSI vectors corresponding to VT-d spec.

Meanwhile, IR MSI test is added to intel IOMMU unit test. The basic IR
test is carried out by a edu INTR raise request. When write to the intr
raise register, interrupt will be generated. Type of interrupt will
depend on the setup (either INTx or MSI).

Suggested-by: Andrew Jones <drjones@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
---
 lib/pci-edu.h         |  1 +
 lib/x86/intel-iommu.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/x86/intel-iommu.h |  1 +
 x86/intel-iommu.c     | 44 +++++++++++++++++++++++-
 4 files changed, 139 insertions(+), 1 deletion(-)

diff --git a/lib/pci-edu.h b/lib/pci-edu.h
index af457df..5be278c 100644
--- a/lib/pci-edu.h
+++ b/lib/pci-edu.h
@@ -32,6 +32,7 @@
 #define EDU_REG_ALIVE               (0x4)
 #define EDU_REG_FACTORIAL           (0x8)
 #define EDU_REG_STATUS              (0x20)
+#define EDU_REG_INTR_RAISE          (0x60)
 #define EDU_REG_DMA_SRC             (0x80)
 #define EDU_REG_DMA_DST             (0x88)
 #define EDU_REG_DMA_COUNT           (0x90)
diff --git a/lib/x86/intel-iommu.c b/lib/x86/intel-iommu.c
index 912a379..1d5f4b2 100644
--- a/lib/x86/intel-iommu.c
+++ b/lib/x86/intel-iommu.c
@@ -12,6 +12,7 @@
 
 #include "intel-iommu.h"
 #include "libcflat.h"
+#include "pci.h"
 
 /*
  * VT-d in QEMU currently only support 39 bits address width, which is
@@ -48,6 +49,26 @@ struct vtd_context_entry {
 } __attribute__ ((packed));
 typedef struct vtd_context_entry vtd_ce_t;
 
+struct vtd_irte {
+	uint32_t present:1;
+	uint32_t fault_disable:1;    /* Fault Processing Disable */
+	uint32_t dest_mode:1;        /* Destination Mode */
+	uint32_t redir_hint:1;       /* Redirection Hint */
+	uint32_t trigger_mode:1;     /* Trigger Mode */
+	uint32_t delivery_mode:3;    /* Delivery Mode */
+	uint32_t __avail:4;          /* Available spaces for software */
+	uint32_t __reserved_0:3;     /* Reserved 0 */
+	uint32_t irte_mode:1;        /* IRTE Mode */
+	uint32_t vector:8;           /* Interrupt Vector */
+	uint32_t __reserved_1:8;     /* Reserved 1 */
+	uint32_t dest_id;            /* Destination ID */
+	uint16_t source_id:16;       /* Source-ID */
+	uint64_t sid_q:2;            /* Source-ID Qualifier */
+	uint64_t sid_vtype:2;        /* Source-ID Validation Type */
+	uint64_t __reserved_2:44;    /* Reserved 2 */
+} __attribute__ ((packed));
+typedef struct vtd_irte vtd_irte_t;
+
 #define VTD_RTA_MASK  (PAGE_MASK)
 #define VTD_IRTA_MASK (PAGE_MASK)
 
@@ -205,6 +226,79 @@ void vtd_map_range(uint16_t sid, iova_t iova, phys_addr_t pa, size_t size)
 	}
 }
 
+static uint16_t vtd_intr_index_alloc(void)
+{
+	static int index_ctr = 0;
+	assert(index_ctr < 65535);
+	return index_ctr++;
+}
+
+static void vtd_setup_irte(struct pci_dev *dev, vtd_irte_t *irte,
+			   int vector, int dest_id)
+{
+	assert(sizeof(vtd_irte_t) == 16);
+	memset(irte, 0, sizeof(*irte));
+	irte->fault_disable = 1;
+	irte->dest_mode = 0;	 /* physical */
+	irte->trigger_mode = 0;	 /* edge */
+	irte->delivery_mode = 0; /* fixed */
+	irte->irte_mode = 0;	 /* remapped */
+	irte->vector = vector;
+	irte->dest_id = dest_id;
+	irte->source_id = dev->bdf;
+	irte->sid_q = 0;
+	irte->sid_vtype = 1;     /* full-sid verify */
+	irte->present = 1;
+}
+
+struct vtd_msi_addr {
+	uint32_t __dont_care:2;
+	uint32_t handle_15:1;	 /* handle[15] */
+	uint32_t shv:1;
+	uint32_t interrupt_format:1;
+	uint32_t handle_0_14:15; /* handle[0:14] */
+	uint32_t head:12;	 /* 0xfee */
+	uint32_t addr_hi;	 /* not used except with x2apic */
+} __attribute__ ((packed));
+typedef struct vtd_msi_addr vtd_msi_addr_t;
+
+struct vtd_msi_data {
+	uint16_t __reserved;
+	uint16_t subhandle;
+} __attribute__ ((packed));
+typedef struct vtd_msi_data vtd_msi_data_t;
+
+/**
+ * vtd_setup_msi - setup MSI message for a device
+ *
+ * @dev: PCI device to setup MSI
+ * @vector: interrupt vector
+ * @dest_id: destination processor
+ */
+bool vtd_setup_msi(struct pci_dev *dev, int vector, int dest_id)
+{
+	vtd_msi_data_t msi_data = {};
+	vtd_msi_addr_t msi_addr = {};
+	vtd_irte_t *irte = phys_to_virt(vtd_ir_table());
+	uint16_t index = vtd_intr_index_alloc();
+
+	assert(sizeof(vtd_msi_addr_t) == 8);
+	assert(sizeof(vtd_msi_data_t) == 4);
+
+	printf("INTR: setup IRTE index %d\n", index);
+	vtd_setup_irte(dev, irte + index, vector, dest_id);
+
+	msi_addr.handle_15 = index >> 15 & 1;
+	msi_addr.shv = 0;
+	msi_addr.interrupt_format = 1;
+	msi_addr.handle_0_14 = index & 0x7fff;
+	msi_addr.head = 0xfee;
+	msi_data.subhandle = 0;
+
+	return pci_setup_msi(dev, *(uint64_t *)&msi_addr,
+			     *(uint32_t *)&msi_data);
+}
+
 void vtd_init(void)
 {
 	setup_vm();
diff --git a/lib/x86/intel-iommu.h b/lib/x86/intel-iommu.h
index 806d9fa..0725f59 100644
--- a/lib/x86/intel-iommu.h
+++ b/lib/x86/intel-iommu.h
@@ -137,5 +137,6 @@ static inline uint64_t vtd_readq(unsigned int reg)
 
 void vtd_init(void);
 void vtd_map_range(uint16_t sid, phys_addr_t iova, phys_addr_t pa, size_t size);
+bool vtd_setup_msi(struct pci_dev *dev, int vector, int dest_id);
 
 #endif
diff --git a/x86/intel-iommu.c b/x86/intel-iommu.c
index 755ccb1..cb9a991 100644
--- a/x86/intel-iommu.c
+++ b/x86/intel-iommu.c
@@ -12,8 +12,10 @@
 
 #include "intel-iommu.h"
 #include "pci-edu.h"
+#include "x86/apic.h"
 
 #define VTD_TEST_DMAR_4B ("DMAR 4B memcpy test")
+#define VTD_TEST_IR_MSI ("IR MSI")
 
 void vtd_test_dmar(struct pci_edu_dev *dev)
 {
@@ -50,6 +52,43 @@ void vtd_test_dmar(struct pci_edu_dev *dev)
 	free_page(page);
 }
 
+static volatile bool edu_intr_recved;
+
+static void edu_isr(isr_regs_t *regs)
+{
+	edu_intr_recved = true;
+	eoi();
+}
+
+static void vtd_test_ir(struct pci_edu_dev *dev)
+{
+#define VTD_TEST_VECTOR (0xee)
+	/*
+	 * Setup EDU PCI device MSI, using interrupt remapping. By
+	 * default, EDU device is using INTx.
+	 */
+	if (!vtd_setup_msi(&dev->pci_dev, VTD_TEST_VECTOR, 0)) {
+		printf("edu device does not support MSI, skip test\n");
+		report_skip(VTD_TEST_IR_MSI);
+		return;
+	}
+
+	handle_irq(VTD_TEST_VECTOR, edu_isr);
+	irq_enable();
+
+	/* Manually trigger INTR */
+	edu_reg_writel(dev, EDU_REG_INTR_RAISE, 1);
+
+	while (!edu_intr_recved)
+		cpu_relax();
+
+	/* Clear INTR bits */
+	edu_reg_writel(dev, EDU_REG_INTR_RAISE, 0);
+
+	/* We are good as long as we reach here */
+	report(VTD_TEST_IR_MSI, true);
+}
+
 int main(int argc, char *argv[])
 {
 	struct pci_edu_dev dev;
@@ -70,8 +109,11 @@ int main(int argc, char *argv[])
 		printf("Please specify \"-device edu\" to do "
 		       "further IOMMU tests.\n");
 		report_skip(VTD_TEST_DMAR_4B);
-	} else
+		report_skip(VTD_TEST_IR_MSI);
+	} else {
 		vtd_test_dmar(&dev);
+		vtd_test_ir(&dev);
+	}
 
 	return report_summary();
 }
-- 
2.7.4


^ permalink raw reply related

* [PATCH kvm-unit-tests v2 15/17] pci: add msi support for 32/64bit address
From: Peter Xu @ 2016-11-09 15:10 UTC (permalink / raw)
  To: kvm; +Cc: drjones, rkrcmar, peterx, agordeev, jan.kiszka, pbonzini
In-Reply-To: <1478704224-20472-1-git-send-email-peterx@redhat.com>

pci_cap_walk() is provided to allow walk through all the capability bits
for a specific PCI device. If a cap handler is provided, it'll be
triggered if the cap is detected along the cap walk.

MSI cap handler is the first one supported. We can add more cap handler
in the future.

Meanwhile, pci_setup_msi() API is provided to support basic 32/64 bit
address MSI setup.

Reviewed-by: Andrew Jones <drjones@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
---
 lib/pci.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/pci.h |  3 +++
 2 files changed, 67 insertions(+)

diff --git a/lib/pci.c b/lib/pci.c
index 971f02e..5b474f2 100644
--- a/lib/pci.c
+++ b/lib/pci.c
@@ -7,6 +7,69 @@
 #include "pci.h"
 #include "asm/pci.h"
 
+typedef void (*pci_cap_handler)(struct pci_dev *dev, int cap_offset);
+
+static void pci_cap_msi_handler(struct pci_dev *dev, int cap_offset)
+{
+	printf("Detected MSI for device 0x%x offset 0x%x\n",
+	       dev->bdf, cap_offset);
+	dev->msi_offset = cap_offset;
+}
+
+static pci_cap_handler cap_handlers[PCI_CAP_ID_MAX + 1] = {
+	[PCI_CAP_ID_MSI] = pci_cap_msi_handler,
+};
+
+void pci_cap_walk(struct pci_dev *dev)
+{
+	uint8_t cap_offset;
+	uint8_t cap_id;
+
+	cap_offset = pci_config_readb(dev->bdf, PCI_CAPABILITY_LIST);
+	while (cap_offset) {
+		cap_id = pci_config_readb(dev->bdf, cap_offset);
+		printf("PCI detected cap 0x%x\n", cap_id);
+		if (cap_handlers[cap_id])
+			cap_handlers[cap_id](dev, cap_offset);
+		cap_offset = pci_config_readb(dev->bdf, cap_offset + 1);
+	}
+}
+
+bool pci_setup_msi(struct pci_dev *dev, uint64_t msi_addr, uint32_t msi_data)
+{
+	uint16_t msi_control;
+	uint16_t offset;
+	pcidevaddr_t addr = dev->bdf;
+
+	assert(dev);
+
+	if (!dev->msi_offset) {
+		printf("MSI: dev 0x%x does not support MSI.\n", addr);
+		return false;
+	}
+
+	offset = dev->msi_offset;
+	msi_control = pci_config_readw(addr, offset + PCI_MSI_FLAGS);
+	pci_config_writel(addr, offset + PCI_MSI_ADDRESS_LO,
+			  msi_addr & 0xffffffff);
+
+	if (msi_control & PCI_MSI_FLAGS_64BIT) {
+		pci_config_writel(addr, offset + PCI_MSI_ADDRESS_HI,
+				  (uint32_t)(msi_addr >> 32));
+		pci_config_writel(addr, offset + PCI_MSI_DATA_64, msi_data);
+		printf("MSI: dev 0x%x init 64bit address: ", addr);
+	} else {
+		pci_config_writel(addr, offset + PCI_MSI_DATA_32, msi_data);
+		printf("MSI: dev 0x%x init 32bit address: ", addr);
+	}
+	printf("addr=0x%lx, data=0x%x\n", msi_addr, msi_data);
+
+	msi_control |= PCI_MSI_FLAGS_ENABLE;
+	pci_config_writew(addr, offset + PCI_MSI_FLAGS, msi_control);
+
+	return true;
+}
+
 void pci_cmd_set_clr(struct pci_dev *dev, uint16_t set, uint16_t clr)
 {
 	uint16_t val = pci_config_readw(dev->bdf, PCI_COMMAND);
@@ -255,5 +318,6 @@ int pci_enable_defaults(struct pci_dev *dev)
 	pci_scan_bars(dev);
 	/* Enable device DMA operations */
 	pci_cmd_set_clr(dev, PCI_COMMAND_MASTER, 0);
+	pci_cap_walk(dev);
 	return 0;
 }
diff --git a/lib/pci.h b/lib/pci.h
index c4fef98..a5a1454 100644
--- a/lib/pci.h
+++ b/lib/pci.h
@@ -23,13 +23,16 @@ enum {
 
 struct pci_dev {
 	uint16_t bdf;
+	uint16_t msi_offset;
 	phys_addr_t bar[PCI_BAR_NUM];
 };
 
 void pci_dev_init(struct pci_dev *dev, pcidevaddr_t bdf);
 void pci_scan_bars(struct pci_dev *dev);
 void pci_cmd_set_clr(struct pci_dev *dev, uint16_t set, uint16_t clr);
+void pci_cap_walk(struct pci_dev *dev);
 int pci_enable_defaults(struct pci_dev *dev);
+bool pci_setup_msi(struct pci_dev *dev, uint64_t msi_addr, uint32_t msi_data);
 
 typedef phys_addr_t iova_t;
 
-- 
2.7.4


^ permalink raw reply related

* [PATCH kvm-unit-tests v2 14/17] x86: intel-iommu: add dmar test
From: Peter Xu @ 2016-11-09 15:10 UTC (permalink / raw)
  To: kvm; +Cc: drjones, rkrcmar, peterx, agordeev, jan.kiszka, pbonzini
In-Reply-To: <1478704224-20472-1-git-send-email-peterx@redhat.com>

DMAR test is based on QEMU edu device. A 4B DMA memory copy is carried
out as the simplest DMAR test.

Signed-off-by: Peter Xu <peterx@redhat.com>
---
 lib/pci.h             |   2 +
 lib/x86/intel-iommu.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/x86/intel-iommu.h |  23 +++++++++
 x86/Makefile.common   |   1 +
 x86/intel-iommu.c     |  50 +++++++++++++++++++
 5 files changed, 207 insertions(+)

diff --git a/lib/pci.h b/lib/pci.h
index 0bdfd8c..c4fef98 100644
--- a/lib/pci.h
+++ b/lib/pci.h
@@ -31,6 +31,8 @@ void pci_scan_bars(struct pci_dev *dev);
 void pci_cmd_set_clr(struct pci_dev *dev, uint16_t set, uint16_t clr);
 int pci_enable_defaults(struct pci_dev *dev);
 
+typedef phys_addr_t iova_t;
+
 extern bool pci_probe(void);
 extern void pci_print(void);
 extern bool pci_dev_exists(pcidevaddr_t dev);
diff --git a/lib/x86/intel-iommu.c b/lib/x86/intel-iommu.c
index 6f52697..912a379 100644
--- a/lib/x86/intel-iommu.c
+++ b/lib/x86/intel-iommu.c
@@ -11,6 +11,42 @@
  */
 
 #include "intel-iommu.h"
+#include "libcflat.h"
+
+/*
+ * VT-d in QEMU currently only support 39 bits address width, which is
+ * 3-level translation.
+ */
+#define VTD_PAGE_LEVEL      (3)
+#define VTD_CE_AW_39BIT     (0x1)
+
+typedef uint64_t vtd_pte_t;
+
+struct vtd_root_entry {
+	/* Quad 1 */
+	uint64_t present:1;
+	uint64_t __reserved:11;
+	uint64_t context_table_p:52;
+	/* Quad 2 */
+	uint64_t __reserved_2;
+} __attribute__ ((packed));
+typedef struct vtd_root_entry vtd_re_t;
+
+struct vtd_context_entry {
+	/* Quad 1 */
+	uint64_t present:1;
+	uint64_t disable_fault_report:1;
+	uint64_t trans_type:2;
+	uint64_t __reserved:8;
+	uint64_t slptptr:52;
+	/* Quad 2 */
+	uint64_t addr_width:3;
+	uint64_t __ignore:4;
+	uint64_t __reserved_2:1;
+	uint64_t domain_id:16;
+	uint64_t __reserved_3:40;
+} __attribute__ ((packed));
+typedef struct vtd_context_entry vtd_ce_t;
 
 #define VTD_RTA_MASK  (PAGE_MASK)
 #define VTD_IRTA_MASK (PAGE_MASK)
@@ -74,6 +110,101 @@ static void vtd_setup_ir_table(void)
 	printf("IR table address: 0x%016lx\n", vtd_ir_table());
 }
 
+static void vtd_install_pte(vtd_pte_t *root, iova_t iova,
+			    phys_addr_t pa, int level_target)
+{
+	int level;
+	unsigned int offset;
+	void *page;
+
+	for (level = VTD_PAGE_LEVEL; level > level_target; level--) {
+		offset = PGDIR_OFFSET(iova, level);
+		if (!(root[offset] & VTD_PTE_RW)) {
+			page = alloc_page();
+			memset(page, 0, PAGE_SIZE);
+			root[offset] = virt_to_phys(page) | VTD_PTE_RW;
+		}
+		root = (uint64_t *)(root[offset] & VTD_PTE_ADDR);
+	}
+
+	offset = PGDIR_OFFSET(iova, level);
+	root[offset] = pa | VTD_PTE_RW;
+	if (level != 1)
+		/* This is huge page */
+		root[offset] |= VTD_PTE_HUGE;
+}
+
+#define  VTD_FETCH_VIRT_ADDR(x) \
+	((void *)(((uint64_t)phys_to_virt(x)) >> PAGE_SHIFT))
+
+/**
+ * vtd_map_range: setup IO address mapping for specific memory range
+ *
+ * @sid: source ID of the device to setup
+ * @iova: start IO virtual address
+ * @pa: start physical address
+ * @size: size of the mapping area
+ */
+void vtd_map_range(uint16_t sid, iova_t iova, phys_addr_t pa, size_t size)
+{
+	uint8_t bus_n, devfn;
+	void *slptptr;
+	vtd_ce_t *ce;
+	vtd_re_t *re = phys_to_virt(vtd_root_table());
+
+	assert(IS_ALIGNED(iova, SZ_4K));
+	assert(IS_ALIGNED(pa, SZ_4K));
+	assert(IS_ALIGNED(size, SZ_4K));
+
+	bus_n = PCI_BDF_GET_BUS(sid);
+	devfn = PCI_BDF_GET_DEVFN(sid);
+
+	/* Point to the correct root entry */
+	re += bus_n;
+
+	if (!re->present) {
+		ce = alloc_page();
+		memset(ce, 0, PAGE_SIZE);
+		memset(re, 0, sizeof(*re));
+		re->context_table_p = virt_to_phys(ce) >> PAGE_SHIFT;
+		re->present = 1;
+		printf("allocated vt-d root entry for PCI bus %d\n",
+		       bus_n);
+	} else
+		ce = VTD_FETCH_VIRT_ADDR(re->context_table_p);
+
+	/* Point to the correct context entry */
+	ce += devfn;
+
+	if (!ce->present) {
+		slptptr = alloc_page();
+		memset(slptptr, 0, PAGE_SIZE);
+		memset(ce, 0, sizeof(*ce));
+		/* To make it simple, domain ID is the same as SID */
+		ce->domain_id = sid;
+		/* We only test 39 bits width case (3-level paging) */
+		ce->addr_width = VTD_CE_AW_39BIT;
+		ce->slptptr = virt_to_phys(slptptr) >> PAGE_SHIFT;
+		ce->trans_type = VTD_CONTEXT_TT_MULTI_LEVEL;
+		ce->present = 1;
+		/* No error reporting yet */
+		ce->disable_fault_report = 1;
+		printf("allocated vt-d context entry for devfn 0x%x\n",
+		       devfn);
+	} else
+		slptptr = VTD_FETCH_VIRT_ADDR(ce->slptptr);
+
+	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",
+		       iova, pa, sid);
+		vtd_install_pte(slptptr, iova, pa, 1);
+		size -= PAGE_SIZE;
+		iova += PAGE_SIZE;
+		pa += PAGE_SIZE;
+	}
+}
+
 void vtd_init(void)
 {
 	setup_vm();
diff --git a/lib/x86/intel-iommu.h b/lib/x86/intel-iommu.h
index d95d76c..806d9fa 100644
--- a/lib/x86/intel-iommu.h
+++ b/lib/x86/intel-iommu.h
@@ -20,6 +20,7 @@
 #include "isr.h"
 #include "smp.h"
 #include "desc.h"
+#include "pci.h"
 #include "asm/io.h"
 
 #define Q35_HOST_BRIDGE_IOMMU_ADDR  0xfed90000ULL
@@ -91,6 +92,27 @@
 #define VTD_GCMD_ONE_SHOT_BITS  (VTD_GCMD_IR_TABLE | VTD_GCMD_WBF | \
 				 VTD_GCMD_SFL | VTD_GCMD_ROOT)
 
+/* Supported Adjusted Guest Address Widths */
+#define VTD_CAP_SAGAW_SHIFT         8
+ /* 39-bit AGAW, 3-level page-table */
+#define VTD_CAP_SAGAW_39bit         (0x2ULL << VTD_CAP_SAGAW_SHIFT)
+ /* 48-bit AGAW, 4-level page-table */
+#define VTD_CAP_SAGAW_48bit         (0x4ULL << VTD_CAP_SAGAW_SHIFT)
+#define VTD_CAP_SAGAW               VTD_CAP_SAGAW_39bit
+
+/* Both 1G/2M huge pages */
+#define VTD_CAP_SLLPS               ((1ULL << 34) | (1ULL << 35))
+
+#define VTD_CONTEXT_TT_MULTI_LEVEL  0
+#define VTD_CONTEXT_TT_DEV_IOTLB    1
+#define VTD_CONTEXT_TT_PASS_THROUGH 2
+
+#define VTD_PTE_R                   (1 << 0)
+#define VTD_PTE_W                   (1 << 1)
+#define VTD_PTE_RW                  (VTD_PTE_R | VTD_PTE_W)
+#define VTD_PTE_ADDR                GENMASK_ULL(51, 12)
+#define VTD_PTE_HUGE                (1 << 7)
+
 #define vtd_reg(reg) ((volatile void *)(Q35_HOST_BRIDGE_IOMMU_ADDR + reg))
 
 static inline void vtd_writel(unsigned int reg, uint32_t value)
@@ -114,5 +136,6 @@ static inline uint64_t vtd_readq(unsigned int reg)
 }
 
 void vtd_init(void);
+void vtd_map_range(uint16_t sid, phys_addr_t iova, phys_addr_t pa, size_t size);
 
 #endif
diff --git a/x86/Makefile.common b/x86/Makefile.common
index 356d879..1dad18b 100644
--- a/x86/Makefile.common
+++ b/x86/Makefile.common
@@ -3,6 +3,7 @@
 all: test_cases
 
 cflatobjs += lib/pci.o
+cflatobjs += lib/pci-edu.o
 cflatobjs += lib/x86/io.o
 cflatobjs += lib/x86/smp.o
 cflatobjs += lib/x86/vm.o
diff --git a/x86/intel-iommu.c b/x86/intel-iommu.c
index f247913..755ccb1 100644
--- a/x86/intel-iommu.c
+++ b/x86/intel-iommu.c
@@ -11,9 +11,49 @@
  */
 
 #include "intel-iommu.h"
+#include "pci-edu.h"
+
+#define VTD_TEST_DMAR_4B ("DMAR 4B memcpy test")
+
+void vtd_test_dmar(struct pci_edu_dev *dev)
+{
+	void *page = alloc_page();
+
+#define DMA_TEST_WORD (0x12345678)
+	/* Modify the first 4 bytes of the page */
+	*(uint32_t *)page = DMA_TEST_WORD;
+
+	/*
+	 * Map the newly allocated page into IOVA address 0 (size 4K)
+	 * of the device address space. Root entry and context entry
+	 * will be automatically created when needed.
+	 */
+	vtd_map_range(dev->pci_dev.bdf, 0, virt_to_phys(page), PAGE_SIZE);
+
+	/*
+	 * DMA the first 4 bytes of the page to EDU device buffer
+	 * offset 0.
+	 */
+	edu_dma(dev, 0, 4, 0, false);
+	/*
+	 * DMA the first 4 bytes of EDU device buffer into the page
+	 * with offset 4 (so it'll be using 4-7 bytes).
+	 */
+	edu_dma(dev, 4, 4, 0, true);
+
+	/*
+	 * Check data match between 0-3 bytes and 4-7 bytes of the
+	 * page.
+	 */
+	report(VTD_TEST_DMAR_4B, *((uint32_t *)page + 1) == DMA_TEST_WORD);
+
+	free_page(page);
+}
 
 int main(int argc, char *argv[])
 {
+	struct pci_edu_dev dev;
+
 	vtd_init();
 
 	report("fault status check", vtd_readl(DMAR_FSTS_REG) == 0);
@@ -22,6 +62,16 @@ int main(int argc, char *argv[])
 	report("IR table setup", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_IR_TABLE);
 	report("DMAR enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_DMAR);
 	report("IR enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_IR);
+	report("DMAR support 39 bits address width",
+	       vtd_readq(DMAR_CAP_REG) & VTD_CAP_SAGAW);
+	report("DMAR support huge pages", vtd_readq(DMAR_CAP_REG) & VTD_CAP_SLLPS);
+
+	if (!edu_init(&dev)) {
+		printf("Please specify \"-device edu\" to do "
+		       "further IOMMU tests.\n");
+		report_skip(VTD_TEST_DMAR_4B);
+	} else
+		vtd_test_dmar(&dev);
 
 	return report_summary();
 }
-- 
2.7.4


^ permalink raw reply related

* [PATCH kvm-unit-tests v2 13/17] pci: edu: introduce pci-edu helpers
From: Peter Xu @ 2016-11-09 15:10 UTC (permalink / raw)
  To: kvm; +Cc: drjones, rkrcmar, peterx, agordeev, jan.kiszka, pbonzini
In-Reply-To: <1478704224-20472-1-git-send-email-peterx@redhat.com>

QEMU edu device is a pci device that is originally written for
educational purpose, however it also suits for IOMMU unit test. Adding
helpers for this specific device to implement the device logic.

The device supports lots of functions, here only DMA operation is
supported.

The spec of the device can be found at:

  https://github.com/qemu/qemu/blob/master/docs/specs/edu.txt

Reviewed-by: Andrew Jones <drjones@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
---
 lib/pci-edu.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/pci-edu.h | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 155 insertions(+)
 create mode 100644 lib/pci-edu.c
 create mode 100644 lib/pci-edu.h

diff --git a/lib/pci-edu.c b/lib/pci-edu.c
new file mode 100644
index 0000000..c9a8b0c
--- /dev/null
+++ b/lib/pci-edu.c
@@ -0,0 +1,73 @@
+/*
+ * Edu PCI device.
+ *
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * Authors:
+ *   Peter Xu <peterx@redhat.com>,
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or
+ * later.
+ */
+
+#include "pci-edu.h"
+#include "asm/barrier.h"
+
+/* Return true if alive */
+static inline bool edu_check_alive(struct pci_edu_dev *dev)
+{
+	static uint32_t live_count = 1;
+	uint32_t value;
+
+	edu_reg_writel(dev, EDU_REG_ALIVE, live_count++);
+	value = edu_reg_readl(dev, EDU_REG_ALIVE);
+	return (live_count - 1 == ~value);
+}
+
+bool edu_init(struct pci_edu_dev *dev)
+{
+	pcidevaddr_t dev_addr;
+
+	dev_addr = pci_find_dev(PCI_VENDOR_ID_QEMU, PCI_DEVICE_ID_EDU);
+	if (dev_addr == PCIDEVADDR_INVALID)
+		return false;
+
+	pci_dev_init(&dev->pci_dev, dev_addr);
+	pci_enable_defaults(&dev->pci_dev);
+	assert(edu_check_alive(dev));
+	return true;
+}
+
+void edu_dma(struct pci_edu_dev *dev, iova_t iova,
+	     size_t size, int dev_offset, bool from_device)
+{
+	uint64_t from, to;
+	uint32_t cmd = EDU_CMD_DMA_START;
+
+	assert(size <= EDU_DMA_SIZE_MAX);
+	assert(dev_offset < EDU_DMA_SIZE_MAX &&
+	       dev_offset >= 0);
+
+	printf("edu device DMA start %s addr %p size 0x%lu off 0x%x\n",
+	       from_device ? "FROM" : "TO",
+	       (void *)iova, size, dev_offset);
+
+	if (from_device) {
+		from = dev_offset + EDU_DMA_START;
+		to = iova;
+		cmd |= EDU_CMD_DMA_FROM;
+	} else {
+		from = iova;
+		to = EDU_DMA_START + dev_offset;
+		cmd |= EDU_CMD_DMA_TO;
+	}
+
+	edu_reg_writeq(dev, EDU_REG_DMA_SRC, from);
+	edu_reg_writeq(dev, EDU_REG_DMA_DST, to);
+	edu_reg_writeq(dev, EDU_REG_DMA_COUNT, size);
+	edu_reg_writel(dev, EDU_REG_DMA_CMD, cmd);
+
+	/* Wait until DMA finished */
+	while (edu_reg_readl(dev, EDU_REG_DMA_CMD) & EDU_CMD_DMA_START)
+		cpu_relax();
+}
diff --git a/lib/pci-edu.h b/lib/pci-edu.h
new file mode 100644
index 0000000..af457df
--- /dev/null
+++ b/lib/pci-edu.h
@@ -0,0 +1,82 @@
+/*
+ * Edu PCI device header.
+ *
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * Authors:
+ *   Peter Xu <peterx@redhat.com>,
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or
+ * later.
+ *
+ * Edu device is a virtualized device in QEMU. Please refer to
+ * docs/specs/edu.txt in QEMU repository for EDU device manual.
+ */
+#ifndef __PCI_EDU_H__
+#define __PCI_EDU_H__
+
+#include "pci.h"
+#include "asm/io.h"
+
+#define  PCI_VENDOR_ID_QEMU              (0x1234)
+#define  PCI_DEVICE_ID_EDU               (0x11e8)
+
+/* The only bar used by EDU device */
+#define EDU_BAR_MEM                 (0)
+#define EDU_MAGIC                   (0xed)
+#define EDU_VERSION                 (0x100)
+#define EDU_DMA_BUF_SIZE            (1 << 20)
+#define EDU_INPUT_BUF_SIZE          (256)
+
+#define EDU_REG_ID                  (0x0)
+#define EDU_REG_ALIVE               (0x4)
+#define EDU_REG_FACTORIAL           (0x8)
+#define EDU_REG_STATUS              (0x20)
+#define EDU_REG_DMA_SRC             (0x80)
+#define EDU_REG_DMA_DST             (0x88)
+#define EDU_REG_DMA_COUNT           (0x90)
+#define EDU_REG_DMA_CMD             (0x98)
+
+#define EDU_CMD_DMA_START           (0x01)
+#define EDU_CMD_DMA_FROM            (0x02)
+#define EDU_CMD_DMA_TO              (0x00)
+
+#define EDU_STATUS_FACTORIAL        (0x1)
+#define EDU_STATUS_INT_ENABLE       (0x80)
+
+#define EDU_DMA_START               (0x40000)
+#define EDU_DMA_SIZE_MAX            (4096)
+
+struct pci_edu_dev {
+	struct pci_dev pci_dev;
+};
+
+#define edu_reg(d, r) (volatile void *)((d)->pci_dev.bar[EDU_BAR_MEM] + (r))
+
+static inline uint64_t edu_reg_readq(struct pci_edu_dev *dev, int reg)
+{
+	return __raw_readq(edu_reg(dev, reg));
+}
+
+static inline uint32_t edu_reg_readl(struct pci_edu_dev *dev, int reg)
+{
+	return __raw_readl(edu_reg(dev, reg));
+}
+
+static inline void edu_reg_writeq(struct pci_edu_dev *dev, int reg,
+				  uint64_t val)
+{
+	__raw_writeq(val, edu_reg(dev, reg));
+}
+
+static inline void edu_reg_writel(struct pci_edu_dev *dev, int reg,
+				  uint32_t val)
+{
+	__raw_writel(val, edu_reg(dev, reg));
+}
+
+bool edu_init(struct pci_edu_dev *dev);
+void edu_dma(struct pci_edu_dev *dev, iova_t iova,
+	     size_t size, int dev_offset, bool from_device);
+
+#endif
-- 
2.7.4


^ permalink raw reply related

* [PATCH kvm-unit-tests v2 12/17] pci: add bdf helpers
From: Peter Xu @ 2016-11-09 15:10 UTC (permalink / raw)
  To: kvm; +Cc: drjones, rkrcmar, peterx, agordeev, jan.kiszka, pbonzini
In-Reply-To: <1478704224-20472-1-git-send-email-peterx@redhat.com>

Signed-off-by: Peter Xu <peterx@redhat.com>
---
 lib/pci.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/lib/pci.h b/lib/pci.h
index 63f8a0a..0bdfd8c 100644
--- a/lib/pci.h
+++ b/lib/pci.h
@@ -18,6 +18,9 @@ enum {
 #define PCI_BAR_NUM                     (6)
 #define PCI_DEVFN_MAX                   (256)
 
+#define PCI_BDF_GET_DEVFN(x)            ((x) & 0xff)
+#define PCI_BDF_GET_BUS(x)              (((x) >> 8) & 0xff)
+
 struct pci_dev {
 	uint16_t bdf;
 	phys_addr_t bar[PCI_BAR_NUM];
-- 
2.7.4


^ permalink raw reply related

* [PATCH kvm-unit-tests v2 11/17] pci: provide pci_enable_defaults()
From: Peter Xu @ 2016-11-09 15:10 UTC (permalink / raw)
  To: kvm; +Cc: drjones, rkrcmar, peterx, agordeev, jan.kiszka, pbonzini
In-Reply-To: <1478704224-20472-1-git-send-email-peterx@redhat.com>

Provide a function to do most of the common PCI init work.

Suggested-by: Andrew Jones <drjones@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
---
 lib/pci.c | 8 ++++++++
 lib/pci.h | 1 +
 2 files changed, 9 insertions(+)

diff --git a/lib/pci.c b/lib/pci.c
index fd17ea5..971f02e 100644
--- a/lib/pci.c
+++ b/lib/pci.c
@@ -249,3 +249,11 @@ void pci_scan_bars(struct pci_dev *dev)
 		dev->bar[i] = pci_bar_get_addr(dev, i);
 	}
 }
+
+int pci_enable_defaults(struct pci_dev *dev)
+{
+	pci_scan_bars(dev);
+	/* Enable device DMA operations */
+	pci_cmd_set_clr(dev, PCI_COMMAND_MASTER, 0);
+	return 0;
+}
diff --git a/lib/pci.h b/lib/pci.h
index de15086..63f8a0a 100644
--- a/lib/pci.h
+++ b/lib/pci.h
@@ -26,6 +26,7 @@ struct pci_dev {
 void pci_dev_init(struct pci_dev *dev, pcidevaddr_t bdf);
 void pci_scan_bars(struct pci_dev *dev);
 void pci_cmd_set_clr(struct pci_dev *dev, uint16_t set, uint16_t clr);
+int pci_enable_defaults(struct pci_dev *dev);
 
 extern bool pci_probe(void);
 extern void pci_print(void);
-- 
2.7.4


^ permalink raw reply related

* [PATCH kvm-unit-tests v2 10/17] pci: provide pci_cmd_set_clr()
From: Peter Xu @ 2016-11-09 15:10 UTC (permalink / raw)
  To: kvm; +Cc: drjones, rkrcmar, peterx, agordeev, jan.kiszka, pbonzini
In-Reply-To: <1478704224-20472-1-git-send-email-peterx@redhat.com>

Helper function to set/clear specific bit in PCI_COMMAND register.

Signed-off-by: Peter Xu <peterx@redhat.com>
---
 lib/pci.c | 12 ++++++++++++
 lib/pci.h |  1 +
 2 files changed, 13 insertions(+)

diff --git a/lib/pci.c b/lib/pci.c
index c063d53..fd17ea5 100644
--- a/lib/pci.c
+++ b/lib/pci.c
@@ -7,6 +7,18 @@
 #include "pci.h"
 #include "asm/pci.h"
 
+void pci_cmd_set_clr(struct pci_dev *dev, uint16_t set, uint16_t clr)
+{
+	uint16_t val = pci_config_readw(dev->bdf, PCI_COMMAND);
+
+	/* No overlap is allowed */
+	assert((set & clr) == 0);
+	val |= set;
+	val &= ~clr;
+
+	pci_config_writew(dev->bdf, PCI_COMMAND, val);
+}
+
 bool pci_dev_exists(pcidevaddr_t dev)
 {
 	return (pci_config_readw(dev, PCI_VENDOR_ID) != 0xffff &&
diff --git a/lib/pci.h b/lib/pci.h
index e452819..de15086 100644
--- a/lib/pci.h
+++ b/lib/pci.h
@@ -25,6 +25,7 @@ struct pci_dev {
 
 void pci_dev_init(struct pci_dev *dev, pcidevaddr_t bdf);
 void pci_scan_bars(struct pci_dev *dev);
+void pci_cmd_set_clr(struct pci_dev *dev, uint16_t set, uint16_t clr);
 
 extern bool pci_probe(void);
 extern void pci_print(void);
-- 
2.7.4


^ permalink raw reply related

* [PATCH kvm-unit-tests v2 09/17] x86/vmexit: leverage pci_scan_bars()
From: Peter Xu @ 2016-11-09 15:10 UTC (permalink / raw)
  To: kvm; +Cc: drjones, rkrcmar, peterx, agordeev, jan.kiszka, pbonzini
In-Reply-To: <1478704224-20472-1-git-send-email-peterx@redhat.com>

Since pci-testdev is a very specific device for QEMU, let's use the new
pci_scan_bars() helper, and selectively choose the bars we want.

Reviewed-by: Andrew Jones <drjones@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
---
 lib/pci.h    |  2 ++
 x86/vmexit.c | 17 ++++++-----------
 2 files changed, 8 insertions(+), 11 deletions(-)

diff --git a/lib/pci.h b/lib/pci.h
index 5ed4e11..e452819 100644
--- a/lib/pci.h
+++ b/lib/pci.h
@@ -68,6 +68,8 @@ int pci_testdev(void);
  * pci-testdev supports at least three types of tests (via mmio and
  * portio BARs): no-eventfd, wildcard-eventfd and datamatch-eventfd
  */
+#define PCI_TESTDEV_BAR_MEM		0
+#define PCI_TESTDEV_BAR_IO		1
 #define PCI_TESTDEV_NUM_BARS		2
 #define PCI_TESTDEV_NUM_TESTS		3
 
diff --git a/x86/vmexit.c b/x86/vmexit.c
index 63fa070..a22f43f 100644
--- a/x86/vmexit.c
+++ b/x86/vmexit.c
@@ -389,17 +389,12 @@ int main(int ac, char **av)
 	ret = pci_find_dev(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_TEST);
 	if (ret != PCIDEVADDR_INVALID) {
 		pci_dev_init(&pcidev, ret);
-		for (i = 0; i < PCI_TESTDEV_NUM_BARS; i++) {
-			if (!pci_bar_is_valid(&pcidev, i)) {
-				continue;
-			}
-			if (pci_bar_is_memory(&pcidev, i)) {
-				membar = pci_bar_get_addr(&pcidev, i);
-				pci_test.memaddr = ioremap(membar, PAGE_SIZE);
-			} else {
-				pci_test.iobar = pci_bar_get_addr(&pcidev, i);
-			}
-		}
+		pci_scan_bars(&pcidev);
+		assert(pci_bar_is_memory(&pcidev, PCI_TESTDEV_BAR_MEM));
+		assert(!pci_bar_is_memory(&pcidev, PCI_TESTDEV_BAR_IO));
+		membar = pcidev.bar[PCI_TESTDEV_BAR_MEM];
+		pci_test.memaddr = ioremap(membar, PAGE_SIZE);
+		pci_test.iobar = pcidev.bar[PCI_TESTDEV_BAR_IO];
 		printf("pci-testdev at 0x%x membar %lx iobar %x\n",
 		       pcidev.bdf, membar, pci_test.iobar);
 	}
-- 
2.7.4


^ permalink raw reply related

* [PATCH kvm-unit-tests v2 08/17] pci: provide pci_scan_bars()
From: Peter Xu @ 2016-11-09 15:10 UTC (permalink / raw)
  To: kvm; +Cc: drjones, rkrcmar, peterx, agordeev, jan.kiszka, pbonzini
In-Reply-To: <1478704224-20472-1-git-send-email-peterx@redhat.com>

Let's provide a more general way to scan PCI bars, rather than read the
config registers every time.

Signed-off-by: Peter Xu <peterx@redhat.com>
---
 lib/pci.c | 13 ++++++++++++-
 lib/pci.h |  3 +++
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/lib/pci.c b/lib/pci.c
index c0bbcba..c063d53 100644
--- a/lib/pci.c
+++ b/lib/pci.c
@@ -206,7 +206,7 @@ static void pci_dev_print(pcidevaddr_t dev)
 	if ((header & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_NORMAL)
 		return;
 
-	for (i = 0; i < 6; i++) {
+	for (i = 0; i < PCI_BAR_NUM; i++) {
 		if (pci_bar_size(&pci_dev, i)) {
 			printf("\t");
 			pci_bar_print(&pci_dev, i);
@@ -226,3 +226,14 @@ void pci_print(void)
 			pci_dev_print(dev);
 	}
 }
+
+void pci_scan_bars(struct pci_dev *dev)
+{
+	int i = 0;
+
+	for (i = 0; i < PCI_BAR_NUM; i++) {
+		if (!pci_bar_is_valid(dev, i))
+			continue;
+		dev->bar[i] = pci_bar_get_addr(dev, i);
+	}
+}
diff --git a/lib/pci.h b/lib/pci.h
index 21f5a7b..5ed4e11 100644
--- a/lib/pci.h
+++ b/lib/pci.h
@@ -15,13 +15,16 @@ enum {
 	PCIDEVADDR_INVALID = 0xffff,
 };
 
+#define PCI_BAR_NUM                     (6)
 #define PCI_DEVFN_MAX                   (256)
 
 struct pci_dev {
 	uint16_t bdf;
+	phys_addr_t bar[PCI_BAR_NUM];
 };
 
 void pci_dev_init(struct pci_dev *dev, pcidevaddr_t bdf);
+void pci_scan_bars(struct pci_dev *dev);
 
 extern bool pci_probe(void);
 extern void pci_print(void);
-- 
2.7.4


^ permalink raw reply related

* [PATCH kvm-unit-tests v2 07/17] pci: introduce struct pci_dev
From: Peter Xu @ 2016-11-09 15:10 UTC (permalink / raw)
  To: kvm; +Cc: drjones, rkrcmar, peterx, agordeev, jan.kiszka, pbonzini
In-Reply-To: <1478704224-20472-1-git-send-email-peterx@redhat.com>

To extend current PCI framework, we need a per-device struct to store
device specific information. Time to have a pci_dev struct. Most of the
current PCI APIs are converted to use this pci_dev object as the first
argument. Currently it only contains one field "bdf", which is the bdf
of current device.

For a few APIs like pci_config_*() ops or pci_find_dev(), I kept the old
interface (use PCI BDF value rather than "struct pci_dev") since they
can be used in a open context that without any specific PCI device.

Signed-off-by: Peter Xu <peterx@redhat.com>
---
 lib/pci-host-generic.c |  9 +++++---
 lib/pci-testdev.c      | 10 +++++----
 lib/pci.c              | 57 ++++++++++++++++++++++++++++++--------------------
 lib/pci.h              | 24 ++++++++++++++-------
 x86/vmexit.c           | 18 +++++++++-------
 5 files changed, 72 insertions(+), 46 deletions(-)

diff --git a/lib/pci-host-generic.c b/lib/pci-host-generic.c
index 6ac0f15..ea83d72 100644
--- a/lib/pci-host-generic.c
+++ b/lib/pci-host-generic.c
@@ -211,6 +211,7 @@ static bool pci_alloc_resource(pcidevaddr_t dev, int bar_num, u64 *addr)
 
 bool pci_probe(void)
 {
+	struct pci_dev pci_dev;
 	pcidevaddr_t dev;
 	u8 header;
 	u32 cmd;
@@ -225,6 +226,8 @@ bool pci_probe(void)
 		if (!pci_dev_exists(dev))
 			continue;
 
+		pci_dev_init(&pci_dev, dev);
+
 		/* We are only interested in normal PCI devices */
 		header = pci_config_readb(dev, PCI_HEADER_TYPE);
 		if ((header & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_NORMAL)
@@ -236,15 +239,15 @@ bool pci_probe(void)
 			u64 addr;
 
 			if (pci_alloc_resource(dev, i, &addr)) {
-				pci_bar_set_addr(dev, i, addr);
+				pci_bar_set_addr(&pci_dev, i, addr);
 
-				if (pci_bar_is_memory(dev, i))
+				if (pci_bar_is_memory(&pci_dev, i))
 					cmd |= PCI_COMMAND_MEMORY;
 				else
 					cmd |= PCI_COMMAND_IO;
 			}
 
-			if (pci_bar_is64(dev, i))
+			if (pci_bar_is64(&pci_dev, i))
 				i++;
 		}
 
diff --git a/lib/pci-testdev.c b/lib/pci-testdev.c
index ad482d3..7d298e6 100644
--- a/lib/pci-testdev.c
+++ b/lib/pci-testdev.c
@@ -163,9 +163,10 @@ static int pci_testdev_all(struct pci_test_dev_hdr *test,
 
 int pci_testdev(void)
 {
+	struct pci_dev pci_dev;
+	pcidevaddr_t dev;
 	phys_addr_t addr;
 	void __iomem *mem, *io;
-	pcidevaddr_t dev;
 	int nr_tests = 0;
 	bool ret;
 
@@ -175,14 +176,15 @@ int pci_testdev(void)
 		       "check QEMU '-device pci-testdev' parameter\n");
 		return -1;
 	}
+	pci_dev_init(&pci_dev, dev);
 
-	ret = pci_bar_is_valid(dev, 0) && pci_bar_is_valid(dev, 1);
+	ret = pci_bar_is_valid(&pci_dev, 0) && pci_bar_is_valid(&pci_dev, 1);
 	assert(ret);
 
-	addr = pci_bar_get_addr(dev, 0);
+	addr = pci_bar_get_addr(&pci_dev, 0);
 	mem = ioremap(addr, PAGE_SIZE);
 
-	addr = pci_bar_get_addr(dev, 1);
+	addr = pci_bar_get_addr(&pci_dev, 1);
 	io = (void *)(unsigned long)addr;
 
 	nr_tests += pci_testdev_all(mem, &pci_testdev_mem_ops);
diff --git a/lib/pci.c b/lib/pci.c
index 6bd54cb..c0bbcba 100644
--- a/lib/pci.c
+++ b/lib/pci.c
@@ -13,16 +13,21 @@ bool pci_dev_exists(pcidevaddr_t dev)
 		pci_config_readw(dev, PCI_DEVICE_ID) != 0xffff);
 }
 
+void pci_dev_init(struct pci_dev *dev, pcidevaddr_t bdf)
+{
+       memset(dev, 0, sizeof(*dev));
+       dev->bdf = bdf;
+}
+
 /* Scan bus look for a specific device. Only bus 0 scanned for now. */
 pcidevaddr_t pci_find_dev(uint16_t vendor_id, uint16_t device_id)
 {
 	pcidevaddr_t dev;
 
-	for (dev = 0; dev < 256; ++dev) {
+	for (dev = 0; dev < PCI_DEVFN_MAX; ++dev)
 		if (pci_config_readw(dev, PCI_VENDOR_ID) == vendor_id &&
 		    pci_config_readw(dev, PCI_DEVICE_ID) == device_id)
 			return dev;
-	}
 
 	return PCIDEVADDR_INVALID;
 }
@@ -33,12 +38,13 @@ uint32_t pci_bar_mask(uint32_t bar)
 		PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK;
 }
 
-uint32_t pci_bar_get(pcidevaddr_t dev, int bar_num)
+uint32_t pci_bar_get(struct pci_dev *dev, int bar_num)
 {
-	return pci_config_readl(dev, PCI_BASE_ADDRESS_0 + bar_num * 4);
+	return pci_config_readl(dev->bdf, PCI_BASE_ADDRESS_0 +
+				bar_num * 4);
 }
 
-phys_addr_t pci_bar_get_addr(pcidevaddr_t dev, int bar_num)
+phys_addr_t pci_bar_get_addr(struct pci_dev *dev, int bar_num)
 {
 	uint32_t bar = pci_bar_get(dev, bar_num);
 	uint32_t mask = pci_bar_mask(bar);
@@ -47,17 +53,18 @@ phys_addr_t pci_bar_get_addr(pcidevaddr_t dev, int bar_num)
 	if (pci_bar_is64(dev, bar_num))
 		addr |= (uint64_t)pci_bar_get(dev, bar_num + 1) << 32;
 
-	return pci_translate_addr(dev, addr);
+	return pci_translate_addr(dev->bdf, addr);
 }
 
-void pci_bar_set_addr(pcidevaddr_t dev, int bar_num, phys_addr_t addr)
+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;
 
-	pci_config_writel(dev, off, (uint32_t)addr);
+	pci_config_writel(dev->bdf, off, (uint32_t)addr);
 
 	if (pci_bar_is64(dev, bar_num))
-		pci_config_writel(dev, off + 4, (uint32_t)(addr >> 32));
+		pci_config_writel(dev->bdf, off + 4,
+				  (uint32_t)(addr >> 32));
 }
 
 /*
@@ -70,20 +77,21 @@ void pci_bar_set_addr(pcidevaddr_t dev, int bar_num, phys_addr_t addr)
  * The following pci_bar_size_helper() and pci_bar_size() functions
  * implement the algorithm.
  */
-static uint32_t pci_bar_size_helper(pcidevaddr_t dev, int bar_num)
+static uint32_t pci_bar_size_helper(struct pci_dev *dev, int bar_num)
 {
 	int off = PCI_BASE_ADDRESS_0 + bar_num * 4;
+	uint16_t bdf = dev->bdf;
 	uint32_t bar, val;
 
-	bar = pci_config_readl(dev, off);
-	pci_config_writel(dev, off, ~0u);
-	val = pci_config_readl(dev, off);
-	pci_config_writel(dev, off, bar);
+	bar = pci_config_readl(bdf, off);
+	pci_config_writel(bdf, off, ~0u);
+	val = pci_config_readl(bdf, off);
+	pci_config_writel(bdf, off, bar);
 
 	return val;
 }
 
-phys_addr_t pci_bar_size(pcidevaddr_t dev, int bar_num)
+phys_addr_t pci_bar_size(struct pci_dev *dev, int bar_num)
 {
 	uint32_t bar, size;
 
@@ -104,19 +112,19 @@ phys_addr_t pci_bar_size(pcidevaddr_t dev, int bar_num)
 	}
 }
 
-bool pci_bar_is_memory(pcidevaddr_t dev, int bar_num)
+bool pci_bar_is_memory(struct pci_dev *dev, int bar_num)
 {
 	uint32_t bar = pci_bar_get(dev, bar_num);
 
 	return !(bar & PCI_BASE_ADDRESS_SPACE_IO);
 }
 
-bool pci_bar_is_valid(pcidevaddr_t dev, int bar_num)
+bool pci_bar_is_valid(struct pci_dev *dev, int bar_num)
 {
 	return pci_bar_get(dev, bar_num);
 }
 
-bool pci_bar_is64(pcidevaddr_t dev, int bar_num)
+bool pci_bar_is64(struct pci_dev *dev, int bar_num)
 {
 	uint32_t bar = pci_bar_get(dev, bar_num);
 
@@ -127,7 +135,7 @@ bool pci_bar_is64(pcidevaddr_t dev, int bar_num)
 		      PCI_BASE_ADDRESS_MEM_TYPE_64;
 }
 
-void pci_bar_print(pcidevaddr_t dev, int bar_num)
+void pci_bar_print(struct pci_dev *dev, int bar_num)
 {
 	phys_addr_t size, start, end;
 	uint32_t bar;
@@ -187,6 +195,9 @@ static void pci_dev_print(pcidevaddr_t dev)
 	uint8_t subclass = pci_config_readb(dev, PCI_CLASS_DEVICE);
 	uint8_t class = pci_config_readb(dev, PCI_CLASS_DEVICE + 1);
 	int i;
+	struct pci_dev pci_dev;
+
+	pci_dev_init(&pci_dev, dev);
 
 	pci_dev_print_id(dev);
 	printf(" type %02x progif %02x class %02x subclass %02x\n",
@@ -196,12 +207,12 @@ static void pci_dev_print(pcidevaddr_t dev)
 		return;
 
 	for (i = 0; i < 6; i++) {
-		if (pci_bar_size(dev, i)) {
+		if (pci_bar_size(&pci_dev, i)) {
 			printf("\t");
-			pci_bar_print(dev, i);
+			pci_bar_print(&pci_dev, i);
 			printf("\n");
 		}
-		if (pci_bar_is64(dev, i))
+		if (pci_bar_is64(&pci_dev, i))
 			i++;
 	}
 }
@@ -210,7 +221,7 @@ void pci_print(void)
 {
 	pcidevaddr_t dev;
 
-	for (dev = 0; dev < 256; ++dev) {
+	for (dev = 0; dev < PCI_DEVFN_MAX; ++dev) {
 		if (pci_dev_exists(dev))
 			pci_dev_print(dev);
 	}
diff --git a/lib/pci.h b/lib/pci.h
index 30f5381..21f5a7b 100644
--- a/lib/pci.h
+++ b/lib/pci.h
@@ -15,6 +15,14 @@ enum {
 	PCIDEVADDR_INVALID = 0xffff,
 };
 
+#define PCI_DEVFN_MAX                   (256)
+
+struct pci_dev {
+	uint16_t bdf;
+};
+
+void pci_dev_init(struct pci_dev *dev, pcidevaddr_t bdf);
+
 extern bool pci_probe(void);
 extern void pci_print(void);
 extern bool pci_dev_exists(pcidevaddr_t dev);
@@ -32,15 +40,15 @@ extern pcidevaddr_t pci_find_dev(uint16_t vendor_id, uint16_t device_id);
  * It is expected the caller is aware of the device BAR layout and never
  * tries to address the middle of a 64-bit register.
  */
-extern phys_addr_t pci_bar_get_addr(pcidevaddr_t dev, int bar_num);
-extern void pci_bar_set_addr(pcidevaddr_t dev, int bar_num, phys_addr_t addr);
-extern phys_addr_t pci_bar_size(pcidevaddr_t dev, int bar_num);
-extern uint32_t pci_bar_get(pcidevaddr_t dev, int bar_num);
+extern phys_addr_t pci_bar_get_addr(struct pci_dev *dev, int bar_num);
+extern void pci_bar_set_addr(struct pci_dev *dev, int bar_num, phys_addr_t addr);
+extern phys_addr_t pci_bar_size(struct pci_dev *dev, int bar_num);
+extern uint32_t pci_bar_get(struct pci_dev *dev, int bar_num);
 extern uint32_t pci_bar_mask(uint32_t bar);
-extern bool pci_bar_is64(pcidevaddr_t dev, int bar_num);
-extern bool pci_bar_is_memory(pcidevaddr_t dev, int bar_num);
-extern bool pci_bar_is_valid(pcidevaddr_t dev, int bar_num);
-extern void pci_bar_print(pcidevaddr_t dev, int bar_num);
+extern bool pci_bar_is64(struct pci_dev *dev, int bar_num);
+extern bool pci_bar_is_memory(struct pci_dev *dev, int bar_num);
+extern bool pci_bar_is_valid(struct pci_dev *dev, int bar_num);
+extern void pci_bar_print(struct pci_dev *dev, int bar_num);
 extern void pci_dev_print_id(pcidevaddr_t dev);
 
 int pci_testdev(void);
diff --git a/x86/vmexit.c b/x86/vmexit.c
index 2d99d5f..63fa070 100644
--- a/x86/vmexit.c
+++ b/x86/vmexit.c
@@ -372,7 +372,8 @@ int main(int ac, char **av)
 	struct fadt_descriptor_rev1 *fadt;
 	int i;
 	unsigned long membar = 0;
-	pcidevaddr_t pcidev;
+	struct pci_dev pcidev;
+	int ret;
 
 	smp_init();
 	setup_vm();
@@ -385,21 +386,22 @@ int main(int ac, char **av)
 	pm_tmr_blk = fadt->pm_tmr_blk;
 	printf("PM timer port is %x\n", pm_tmr_blk);
 
-	pcidev = pci_find_dev(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_TEST);
-	if (pcidev != PCIDEVADDR_INVALID) {
+	ret = pci_find_dev(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_TEST);
+	if (ret != PCIDEVADDR_INVALID) {
+		pci_dev_init(&pcidev, ret);
 		for (i = 0; i < PCI_TESTDEV_NUM_BARS; i++) {
-			if (!pci_bar_is_valid(pcidev, i)) {
+			if (!pci_bar_is_valid(&pcidev, i)) {
 				continue;
 			}
-			if (pci_bar_is_memory(pcidev, i)) {
-				membar = pci_bar_get_addr(pcidev, i);
+			if (pci_bar_is_memory(&pcidev, i)) {
+				membar = pci_bar_get_addr(&pcidev, i);
 				pci_test.memaddr = ioremap(membar, PAGE_SIZE);
 			} else {
-				pci_test.iobar = pci_bar_get_addr(pcidev, i);
+				pci_test.iobar = pci_bar_get_addr(&pcidev, i);
 			}
 		}
 		printf("pci-testdev at 0x%x membar %lx iobar %x\n",
-		       pcidev, membar, pci_test.iobar);
+		       pcidev.bdf, membar, pci_test.iobar);
 	}
 
 	for (i = 0; i < ARRAY_SIZE(tests); ++i)
-- 
2.7.4


^ permalink raw reply related

* [PATCH kvm-unit-tests v2 06/17] vm/page: provide PGDIR_OFFSET() macro
From: Peter Xu @ 2016-11-09 15:10 UTC (permalink / raw)
  To: kvm; +Cc: drjones, rkrcmar, peterx, agordeev, jan.kiszka, pbonzini
In-Reply-To: <1478704224-20472-1-git-send-email-peterx@redhat.com>

This can be used in further patches.

Reviewed-by: Andrew Jones <drjones@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
---
 lib/x86/asm/page.h | 3 +++
 lib/x86/vm.c       | 4 ++--
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/lib/x86/asm/page.h b/lib/x86/asm/page.h
index 5044a49..c43bab2 100644
--- a/lib/x86/asm/page.h
+++ b/lib/x86/asm/page.h
@@ -41,5 +41,8 @@
 #define	PGDIR_MASK	1023
 #endif
 
+#define PGDIR_BITS(lvl)        (((lvl) - 1) * PGDIR_WIDTH + PAGE_SHIFT)
+#define PGDIR_OFFSET(va, lvl)  (((va) >> PGDIR_BITS(lvl)) & PGDIR_MASK)
+
 #endif /* !__ASSEMBLY__ */
 #endif
diff --git a/lib/x86/vm.c b/lib/x86/vm.c
index f7e778b..cda4c5f 100644
--- a/lib/x86/vm.c
+++ b/lib/x86/vm.c
@@ -48,7 +48,7 @@ unsigned long *install_pte(unsigned long *cr3,
     unsigned offset;
 
     for (level = PAGE_LEVEL; level > pte_level; --level) {
-	offset = ((unsigned long)virt >> ((level-1) * PGDIR_WIDTH + 12)) & PGDIR_MASK;
+	offset = PGDIR_OFFSET((unsigned long)virt, level);
 	if (!(pt[offset] & PT_PRESENT_MASK)) {
 	    unsigned long *new_pt = pt_page;
             if (!new_pt)
@@ -60,7 +60,7 @@ unsigned long *install_pte(unsigned long *cr3,
 	}
 	pt = phys_to_virt(pt[offset] & PT_ADDR_MASK);
     }
-    offset = ((unsigned long)virt >> ((level-1) * PGDIR_WIDTH + 12)) & PGDIR_MASK;
+    offset = PGDIR_OFFSET((unsigned long)virt, level);
     pt[offset] = pte;
     return &pt[offset];
 }
-- 
2.7.4


^ permalink raw reply related

* [PATCH kvm-unit-tests v2 05/17] libcflat: moving MIN/MAX here
From: Peter Xu @ 2016-11-09 15:10 UTC (permalink / raw)
  To: kvm; +Cc: drjones, rkrcmar, peterx, agordeev, jan.kiszka, pbonzini
In-Reply-To: <1478704224-20472-1-git-send-email-peterx@redhat.com>

That's something can be used outside alloc.c.

Reviewed-by: Andrew Jones <drjones@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
---
 lib/alloc.c    | 3 ---
 lib/libcflat.h | 3 +++
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/alloc.c b/lib/alloc.c
index e1d7b8a..58af52b 100644
--- a/lib/alloc.c
+++ b/lib/alloc.c
@@ -7,9 +7,6 @@
 #include "asm/spinlock.h"
 #include "asm/io.h"
 
-#define MIN(a, b)		((a) < (b) ? (a) : (b))
-#define MAX(a, b)		((a) > (b) ? (a) : (b))
-
 #define PHYS_ALLOC_NR_REGIONS	256
 
 struct phys_alloc_region {
diff --git a/lib/libcflat.h b/lib/libcflat.h
index dd600b7..9b92e66 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -40,6 +40,9 @@
 #define SZ_2M			(0x200000)
 #define SZ_1G			(0x40000000)
 
+#define MIN(a, b)		((a) < (b) ? (a) : (b))
+#define MAX(a, b)		((a) > (b) ? (a) : (b))
+
 typedef uint8_t		u8;
 typedef int8_t		s8;
 typedef uint16_t	u16;
-- 
2.7.4


^ permalink raw reply related

* [PATCH kvm-unit-tests v2 02/17] libcflat: introduce is_power_of_2()
From: Peter Xu @ 2016-11-09 15:10 UTC (permalink / raw)
  To: kvm; +Cc: drjones, rkrcmar, peterx, agordeev, jan.kiszka, pbonzini
In-Reply-To: <1478704224-20472-1-git-send-email-peterx@redhat.com>

Suggested-by: Andrew Jones <drjones@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
---
 lib/libcflat.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/libcflat.h b/lib/libcflat.h
index 72b1bf9..19bd0c6 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -103,4 +103,9 @@ do {									\
 	}								\
 } while (0)
 
+static inline bool is_power_of_2(unsigned long n)
+{
+	return (n && !(n & (n - 1)));
+}
+
 #endif
-- 
2.7.4


^ permalink raw reply related


This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.