Xen Security Advisory 295 v1 - Unlimited Arm Atomics Operations

Xen.org security team <[email protected]>
Newsgroups gmane.comp.emulators.xen.announce
Message-ID <E1hbVCg-0002Rc-38__46374.175213144$1565609921$gmane$org@xenbits.xenproject.org>
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

                    Xen Security Advisory XSA-295

                  Unlimited Arm Atomics Operations

ISSUE DESCRIPTION
=================

Software targeting pre-Armv8.1-A hardware, Xen included, commonly
implements atomics using Load/Store exclusive instructions in a loop
that will terminate once the store succeeded.

As per the Armv8-A Architecture Reference Manual (ARM DDI0487D.a),
paragraph 2.9.5 "Load-Exclusive and Store-Exclusive instruction usage
restrictions", page B2-143:

"""
It is permissible for the LoadExcl / StoreExcl loop not to make
forward progress if a different thread is repeatedly doing any of the
following in a tight loop:
- - Performing stores to a PA covered by the Exclusives monitor.
- - Prefetching with intent to write to a PA covered by the Exclusives
  monitor.
- - Executing data cache clean, data cache invalidate, or data cache clean
  and invalidate instructions to a
  PA covered by the Exclusives monitor.
- - Executing instruction cache invalidate all instructions.
- - Executing instruction cache invalidate by VA instructions to a PA
  covered by the Exclusives monitor.
"""

The underlying LoadExcl or StoreExcl operation might never succeed,
resulting in an unlimited loop in the hypervisor.

A similar, but independent, issue occurs when compare-and-exchange
operations are misused:

 do
 {
   old = *addr;
 }
 while (cmpxchg(addr, old, new) != new);

This pattern is not safe, because the operation may continuously fail if
another thread in a guest is continuously modifying the value. An
instance of this pattern was found in Xen.


IMPACT
======

An attacker in a domU could perform a denial of service attack on Xen by
accessing a memory region shared with the hypervisor, while Xen is
performing an atomic operation on the same region. As a result Xen could
end up looping boundlessly. See the issue description for more details
on the memory accesses that affect LoadExcl and StoreExcl operations.


VULNERABLE SYSTEMS
==================

Systems running all versions of Xen are affected.

x86 processors are not affected.
Arm processors are vulnerable, both Armv7 and Armv8.


NOTE REGARDING LACK OF EMBARGO
==============================

Other Open Source projects released fixes to the public before we could
arrange for an organized disclosure.


MITIGATION
==========

There are no mitigations.


CREDITS
=======

This issue was discovered by Andrew Cooper of Citrix and Julien Grall of
Arm.


RESOLUTION
==========

Applying the appropriate attached patches resolve this issue.

Please note that these patches enable SILO mode by default, which denies
communications between unprivileged guests. Page sharing between domUs,
thus inter-domains communications and driver domains, are not allowed by
SILO mode. It is necessary to have a complete fix to this vulnerability.

SILO mode is required because the fix relies on Xen being able to
pinpoint the domain owner of the shared page. Without SILO mode, a guest
could share a page with Xen and with a second guest (e.g via grant
table): the second guest could use the foreign page to attack the
hypervisor.

Users are encouraged to write their own Flask policies to enable more
complex configurations. For example, Flask could be used to allow page
sharing between trusted virtual machines (trusted by the administrator).

xsa295/unstable-*.patch         xen-unstable
xsa295/4.12-*.patch             Xen 4.12.x
xsa295/4.11-*.patch             Xen 4.11.x
xsa295/4.10-*.patch             Xen 4.10.x
xsa295/4.9-*.patch              Xen 4.9.x
xsa295/4.8-*.patch              Xen 4.8.x

$ sha256sum xsa295* xsa295*/*
697d0e7d2535b573596087cc0228891d7cb48a3dd2527e1d277bf501132403f4  xsa295.meta
d3205f79cc2dd34a7359cf7c692dd5c00c3e488ccbb503fdd93606133a15aeb9  xsa295/4.8-01.patch
995ac1a3a4fb7e8ef48664fec8a98963ee84582c1b70ece36ddeaa8889a63274  xsa295/4.8-02.patch
9b30579cd9043aff58626da159f58519795323d2a6e8dde86b4e5ca667c64828  xsa295/4.8-03.patch
63cbc7cae8636f496dbf6c743eda2dbc8acdcdcd010546f362f39c461d064b7e  xsa295/4.8-04.patch
174ce3aadcf28f241106c506e1494ad1343f924e747e8f86073ab375803e15e2  xsa295/4.8-05.patch
c5d18e3471a9d7dd3f5cef3f56ecb8b54a2a836c4529e9247d1c15332fc6eec9  xsa295/4.8-06.patch
ebe7a57cc436004cb0bcd3acc9e37a4e8c4b76cc9fde5811587758260bd8ce01  xsa295/4.8-07.patch
4b45b2e741edc33eb2ed7f55994b12ef7bddd65c8c89856ceba373704a1add03  xsa295/4.8-08.patch
8493a5367589988310681b09d775009c6feabb696a308f69ae6cb254d445d80d  xsa295/4.8-09.patch
dd226d28c19b2dc2bc68ebb03d7f573273506ce96c3b31a4f627f9682b32f094  xsa295/4.8-10.patch
70af876fb95e11b73a532fa560ddf0e2057668526455618da54faef5aaa19908  xsa295/4.8-11.patch
97ad268d6be9becb6718e688517bb9e8ded2781e62a384383d7d089833c4af75  xsa295/4.8-12.patch
d6885314e52daaf27403a013f896a3a55c4faefa74989047aff90e97368125e7  xsa295/4.8-13.patch
7639b0eb9bdc02fe324163c40ce913e886a56d523435cc6977e268ad81dcc4fe  xsa295/4.8-14.patch
1835d88402ce9095c37c604fc5b20f8b48d1c2e15d320336e7b1c11c0f0bad82  xsa295/4.8-15.patch
54346a21cdda49a403244d223e552384557f3f09ef4a5aa3d5e3efa989a9bd27  xsa295/4.8-16.patch
07ebef935818163e29621d7bc319ae599e0f0347cf585b9a463ae36a809954c7  xsa295/4.8-17.patch
7106193d65afc7c43f7aa4d92e12d8374117b9364acb59d84f5687eb19ad1aee  xsa295/4.8-18.patch
70fad082b2c921c3c01ee2a46cd0826a7e96e90b423322f3abf7d42535f74a53  xsa295/4.8-19.patch
c9f3cf4ae11de9347fe385c75714f2fb03f63e165253b80ba00d2138ccc424b4  xsa295/4.8-20.patch
fc2fb134941e45849d66b7ac41915d4188fa692ad679bbc982d8a13f4cca459e  xsa295/4.8-21.patch
9f9aba779f1ec0e50a13f6c4ea57bf69bcb98bc06a3c1612bc70b0e579e4e67e  xsa295/4.9-01.patch
8b853a24049f419413b8854bf2ccbb21cb2f730083f70878d5ed9b9e16943a9e  xsa295/4.9-02.patch
b1658c003d1c15444c11119b4f5d11fdbb0fea3d86a3611e37fe763eff53ed11  xsa295/4.9-03.patch
3fb7cf8d10a0c6c7dc597fe86ed22aa63a65bc6c6a55a8a4eb36d92b524c84c9  xsa295/4.9-04.patch
73e3796e4a159dcb670e315ded2dc3cce4bc6aec805300906fd9f82ff246144f  xsa295/4.9-05.patch
b07f7aa9f18434ae49cbbdbc67e63ae20fd12b06dc2a564a8b2f12fb45ac9766  xsa295/4.9-06.patch
09ac28c464dea4438714691d93d7b6dfeb06f00a482a46e3f6f20e0f5fd9c24e  xsa295/4.9-07.patch
492d2f5691ba330290c61c497d9da5c7681da046c4da06c0e3c90fe8ddfe5fed  xsa295/4.9-08.patch
5dc39df41cfc3f5dde06f6c4eb7044d6ff1d655285a650ecab01dc93ec625908  xsa295/4.9-09.patch
a5f1813ae070efe7508f1a128c197f6b0c6fe72d206a48597407c77bae434490  xsa295/4.9-10.patch
b603b7e6eb2b5f6a5ac17ce12fede6f4e804f36d8c352e70433f93068d99d15b  xsa295/4.9-11.patch
dd4e444355797dc0eb29de3f50a00b6fe02e29bc2675e5fb286f448f2d14bb03  xsa295/4.9-12.patch
e4a659e259d16150441041b08433c423fe8ab1e13fb2496ba887733fabd23654  xsa295/4.9-13.patch
2230d8930aff9dcafa46f643d1b9e4d405edf0a0c5639a28e8f5c929154ad093  xsa295/4.9-14.patch
087a022013cf8e0b05b957702500505eea08a9236efb2df4e3b475e8fa6257d6  xsa295/4.9-15.patch
acf80303cb5d59a42ec46d6b1bc5352ee9c013ca8688ae05c2d3192b68479ce5  xsa295/4.9-16.patch
6ffc97f683b906848697b5b0781741c7f180c5a37da4b59e042f43b9cbf7d0ff  xsa295/4.9-17.patch
c5b4fcf27fef8cbfde888794b1f6a8feec555afea7d702bbb87580ffcea18409  xsa295/4.9-18.patch
3d72dfa40832045f141e9f66f8b10d1cd54d4117df3a8590447ae0523b98efb3  xsa295/4.9-19.patch
aba4702d8bcff9bb6397cf24b2c347532052a91d19269f6ada30bd490a5fa873  xsa295/4.9-20.patch
a9872522ad97da690ffe82888c9f5b68f225a80396a8bcee6c4819b1bbf98604  xsa295/4.10-01.patch
6a3b764546ee0350318f0c95f617604d9805bde68357a3b89232768e8b6fbeff  xsa295/4.10-02.patch
73c72344ac6fc05db85d73c1cfb28302fe3e73a01d450eb4360bbced78f16b05  xsa295/4.10-03.patch
9ce62928555859e4689645a251f6501726bf36fc3c4250579d66afc36a22d424  xsa295/4.10-04.patch
21e5d8817b9b5afd13efff4efa72dabfe56dfed3e44241355816ffe65d02b179  xsa295/4.10-05.patch
b9288a8a7cdfdc2a36051f16850c3dd792f0b19ea9cc297acdbcb9b2223b0051  xsa295/4.10-06.patch
1d7b7dbfe26853f36b434370ddd2e474ae16d40fd958b2148fa08dc46f6c8e48  xsa295/4.10-07.patch
220546808af75e8306a4cc6a069db3cf1c1b1a5a355a62a504333222957ca5d8  xsa295/4.10-08.patch
0687490d095b175ab2c1cf86b1eb8f6533fb06b03c374499ed4bea938e611cd4  xsa295/4.10-09.patch
eb6f44dcd14aa7ebe481f6144fca845707ca6fc1f44391a88a25779cf06e6424  xsa295/4.10-10.patch
62c8eb33864e72006e31c25ff5bd222e0c40542d5e851366c8360c68d9d54294  xsa295/4.10-11.patch
f87a658afca43c9bd7e24ad31fcf1559e5dd4412397a70812b56f002956e5351  xsa295/4.10-12.patch
4448828b6bdfd805a4704f90481b3c0071b6ce68b48d0e1d87413c92870e143d  xsa295/4.10-13.patch
75e1524c6be1141c428cc37ec793de3af361e428f3e2077135f5a677166c53f6  xsa295/4.10-14.patch
0670dd8bd1914d88d2e602d01e91d0115181dbe3c6c2edd917cef8c4b56cb692  xsa295/4.10-15.patch
6464077fae9fbf5b946309dc54f6b2b8b8182c606bdafd73813394cd0e6c2b8a  xsa295/4.10-16.patch
e38bd1a2f251526d439bcefcab857ea8bbd18285fbe033410e1ef760d2ee7962  xsa295/4.10-17.patch
b349b5da41ef94a71d8c473ec08f4785024e93f2d3d69842a0a25f8e5cc79779  xsa295/4.10-18.patch
0c02c336c245be5ab9e9a9dca071750f1e4ce32e5bb09561989964fcd492ea81  xsa295/4.10-19.patch
c2c9b558dee16f3f994bfe33ed29caa5f4b5ef58be2eba91ce5e7bf1ba893d15  xsa295/4.10-20.patch
877e4bf9c4f102b1b11118cca2f328f2bf7b41270661e5390b687126ff74b7ea  xsa295/4.11-01.patch
8828b593a291aa264863734809d87bb40e311a5572e26439f1dd49d9aa5014d5  xsa295/4.11-02.patch
85288a06596ffdfaf9426e775c4d8f2d9be8d9a0804ea76728ed8e4098125142  xsa295/4.11-03.patch
d8d48305ff0c7bdb4597c4959c646634522de58c2822679ec2d0f6f4745cffa1  xsa295/4.11-04.patch
d54609119a03b1c53f3808f0656e3ce79093b222643170fd785787898c663321  xsa295/4.11-05.patch
c9e199287df3cf0dfa8bb52789b520bad8787fb974685bc2c3c7a27c8ff301c3  xsa295/4.11-06.patch
8b2d0375fd9ea3cb8cad8875448ec6669b7522355da17ff11e52a701468e72ce  xsa295/4.11-07.patch
c3462a37673aadde2bd7230afd8a47111dda5368dff193ada7d107880f66ba21  xsa295/4.11-08.patch
7df8c127a45b7a7a50aa4c95d239b44bf022e2ea4e775a8da3b807482bfe81c6  xsa295/4.11-09.patch
244fa2153b8d55ba971b447365c329dfe286bbe773b3b006f34c822c21aa879b  xsa295/4.11-10.patch
2669b7dbe75260f4b6271d88acc42675e022045f7287f2c503fab0d906d50c5a  xsa295/4.11-11.patch
f864bb6dd86cfcf6aefded4f4880b478bd19978a8dde515dffcbee5ef148455e  xsa295/4.11-12.patch
06d968f993ddb72417ba69a2d40a08978cef310a9857b371d037d5bb0172e2f8  xsa295/4.11-13.patch
1ca901e0749609de29bddd39ca00986820cd29967ba1bddd56baef2e00984324  xsa295/4.11-14.patch
7268bd14fb09f9549609c18a3c343e5d60861266e945b283bab88692b26f0f64  xsa295/4.11-15.patch
fb900e58c372a96bbb08ee7b0bda1289a31082675095d2f05775a91b8c76fca1  xsa295/4.11-16.patch
072c5840a5ca99383be2cfb5bf15b233dc132a62cbb500d7c8e43b7602b84bfa  xsa295/4.11-17.patch
64b4b10209e3856dbbba7e4ce650de5c81e543e493efb6d7dc9ff4c349f8433c  xsa295/4.11-18.patch
3fe4ee39b93fb54a4bebb6944724e2db9bd3829cfdd47d58f66b797bc3c3e7dc  xsa295/4.11-19.patch
b480df66dcbae4c06e6e1311b2d84b9b8b5397978d0ce97db65e813e4af6a368  xsa295/4.11-20.patch
f9ee8d83060b9389fb781e0f8ed5cfb65b5832e2f28b0c8d92c6dd5f3c8ec6b9  xsa295/4.12-01.patch
f1682b9eb028fadbe45e0570ec1c2f22bbd9259cc774220f06bc5c68e49c5679  xsa295/4.12-02.patch
2a4305b103f420abaed5e906e20041f833a62fb72f16b2b78563368c6e0d3313  xsa295/4.12-03.patch
daa9e6dd1c4600449f3ec552fb9143e79de5027c84e89998b663d74eaa8999e4  xsa295/4.12-04.patch
79b7d9bb516415665c257d267937aac193e233d29ae068f227754f3dd3769c02  xsa295/4.12-05.patch
c56fde989d3a18b16a526546ec9f8098eb4c4f4d85e98f5b49cda18cefad9d92  xsa295/4.12-06.patch
840f9a8c65da834a590850fe7300334e9066a40eb43a35a15b4fefe4e898736d  xsa295/4.12-07.patch
103067f269a694af8ae3fb83cc1923bbf8aea5283216ac70a6a2191e64d8e978  xsa295/4.12-08.patch
95ca3b81360f2372daf2d6999623f296ee54493341d8dcba862750bfd9980e78  xsa295/4.12-09.patch
3d2620e73531dc2b1f2731ea73d992a754233de2f23a9b908db52f944b2f8cd4  xsa295/4.12-10.patch
b75e38d8d38d9b604dd6e94e790cfd2703cf029a507527744fee9514b25346aa  xsa295/4.12-11.patch
7f5cfae93d930cb085e053013f0008a98ca0e4ae14a616e112470f994db87809  xsa295/4.12-12.patch
7d247d7207d96da1fc1be4e309be0e3fec273bc2c7401903a1dcc8b2cfd8831e  xsa295/4.12-13.patch
9bbf771a4b10aa64e55fe8d5c6d1e4babb03707b8373520fad6c59b3c77514fe  xsa295/4.12-14.patch
fc8af641c4926184785ac5f742ec8afaeeb883ba5a21cf171a814e6ba7955176  xsa295/4.12-15.patch
a16189f5c743283f2cce8d346d8c47c950c874705427947f79cd65d78ecd0c5c  xsa295/4.12-16.patch
e06d5caf859920625bd955b53ade9d2cba314d32ceb41fdc63aba4974bcdc5a2  xsa295/4.12-17.patch
ce0ef520e70907b53d132be34d319606f234b22a331cdc132e5511b49775e516  xsa295/unstable-01.patch
ab0ceb33ab640f51b8a42b85c2b0ada395b7ce10597a81534447a6cd4f15342d  xsa295/unstable-02.patch
eb4681d172bf17c5023235dce4191cca69ba72f3664ed80e7c180101015c4960  xsa295/unstable-03.patch
788377a285d0b57619c4e3ca35b88a0fc3f9f0823a5675d5c6de0eb488c79a26  xsa295/unstable-04.patch
1886b2b45a9be0d50c2f1bdbe20657e6a3d3b3634c0f4bd093fb4e70342a6fdc  xsa295/unstable-05.patch
a33d4c969e2d22d9c56135b1c97cb440724ba27af786c211a3287a1981abc30a  xsa295/unstable-06.patch
b9fc6a5a2e72dbe821f03819ce6c4b0edf07fd876cafbefc36d759099b65396e  xsa295/unstable-07.patch
1185d465944418de5fc1d100f506905a629228722020f37d58d23c6bb67e92e3  xsa295/unstable-08.patch
26eda405b47c4b0c5efddb4fd99ed2c200cf0064d6fc26c5eab2fe2485241274  xsa295/unstable-09.patch
9fa8d50da43782b1032eac0b672a1e81fdce70bc5826b959003d3fc84724fddd  xsa295/unstable-10.patch
59592868ac1cde2e72ec347715a204ffe95b434d445ce21d63eb70866f2c0298  xsa295/unstable-11.patch
84f55da76a8788bfe9667cd7aa7e2c9fd046903388e818afb18e5b78b161d67b  xsa295/unstable-12.patch
9d3992567ede2ab61675de19a22d19e3e67b67e5f9bac7812e4551f55766cde6  xsa295/unstable-13.patch
c9f07ae61870d09e68f621b6d68943c9bcd041af3a71ba7fe42578cb9d1c6748  xsa295/unstable-14.patch
5b4c18f5f11401cf2d4421f27d93bb92053e78da1f88f371f381287298c29fa9  xsa295/unstable-15.patch
-----BEGIN PGP SIGNATURE-----

iQFABAEBCAAqFiEEI+MiLBRfRHX6gGCng/4UyVfoK9kFAl0CGhIMHHBncEB4ZW4u
b3JnAAoJEIP+FMlX6CvZGkYIAMtEB5xEF+r/oMiD4dH6eiDaktjANRpNnJQ5IGB/
KMZTzAzz9Yoj+smyVQkSqnuXusB+E/Yb8lFNgnV/dPrBLmraI9K/BPVxOR1KrtE/
Cy3RUXcjEy6lAdVGf/Y25WGGJVwRU3ii4kcallzrzOTxFweecOhOwPJj7L+i3rcv
hOMqydvtJ2f8r/A5yqmqFFzF4WL7LTfAgmkIdS0tJl3V6qnICo9IoMnR8wKkgIMY
1+kMieYtzCTQPC2Q1ZpJtnr1bUeumrpcpw3Fti+DQaTz9Y0JB+w/WClaLAtinyql
IAzTLeozCU52cgFJqIvusXMQQA4lSnkwfGskVg4ygR8rYRk=
=P7nz
-----END PGP SIGNATURE-----
xsa295.meta (application/octet-stream, 1.6 KB) - not displayed
xsa295/4.8-01.patch (application/octet-stream, 2.3 KB)
From 299714811f2474d5c3a86029611ccc3d2b763e8d Mon Sep 17 00:00:00 2001
From: Jan Beulich <[email protected]>
Date: Thu, 23 May 2019 10:42:29 -0700
Subject: [PATCH v2 4.8 01/21] events: drop arch_evtchn_inject()

Have the only user call vcpu_mark_events_pending() instead, at the same
time arranging for correct ordering of the writes (evtchn_pending_sel
should be written before evtchn_upcall_pending).

Signed-off-by: Jan Beulich <[email protected]>
Reviewed-by: Andrew Cooper <[email protected]>
Reviewed-by: Julien Grall <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/vgic.c     | 5 -----
 xen/common/domain.c     | 3 +--
 xen/include/xen/event.h | 3 ---
 3 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 60af06805d..53d43b49a1 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -537,11 +537,6 @@ void vgic_vcpu_inject_spi(struct domain *d, unsigned int virq)
     vgic_vcpu_inject_irq(v, virq);
 }
 
-void arch_evtchn_inject(struct vcpu *v)
-{
-    vgic_vcpu_inject_irq(v, v->domain->arch.evtchn_irq);
-}
-
 int vgic_emulate(struct cpu_user_regs *regs, union hsr hsr)
 {
     struct vcpu *v = current;
diff --git a/xen/common/domain.c b/xen/common/domain.c
index b574551188..314f880a92 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -1206,10 +1206,9 @@ int map_vcpu_info(struct vcpu *v, unsigned long gfn, unsigned offset)
      * Mark everything as being pending just to make sure nothing gets
      * lost.  The domain will get a spurious event, but it can cope.
      */
-    vcpu_info(v, evtchn_upcall_pending) = 1;
     for ( i = 0; i < BITS_PER_EVTCHN_WORD(d); i++ )
         set_bit(i, &vcpu_info(v, evtchn_pending_sel));
-    arch_evtchn_inject(v);
+    vcpu_mark_events_pending(v);
 
     return 0;
 }
diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h
index 82caddbe76..945c2e7049 100644
--- a/xen/include/xen/event.h
+++ b/xen/include/xen/event.h
@@ -68,9 +68,6 @@ int guest_enabled_event(struct vcpu *v, uint32_t virq);
 /* Notify remote end of a Xen-attached event channel.*/
 void notify_via_xen_event_channel(struct domain *ld, int lport);
 
-/* Inject an event channel notification into the guest */
-void arch_evtchn_inject(struct vcpu *v);
-
 /*
  * Internal event channel object storage.
  *
-- 
2.17.1
xsa295/4.8-02.patch (application/octet-stream, 1.4 KB)
From e74c5787940999766ae8cd9731471370b595c3fe Mon Sep 17 00:00:00 2001
From: Andre Przywara <[email protected]>
Date: Thu, 16 Mar 2017 11:20:10 +0000
Subject: [PATCH v2 4.8 02/21] ARM: arm64: activate atomic 64-bit accessors

For some reason (probably because there was no user before) the 64-bit
atomic access wrappers were commented out so far.
As we will need them in the next patch, active (and fix) them now.

Signed-off-by: Andre Przywara <[email protected]>
Reviewed-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/atomic.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/xen/include/asm-arm/atomic.h b/xen/include/asm-arm/atomic.h
index 22a50361ec..df9de6a74a 100644
--- a/xen/include/asm-arm/atomic.h
+++ b/xen/include/asm-arm/atomic.h
@@ -53,9 +53,9 @@ build_atomic_write(write_u16_atomic, "h", WORD, uint16_t, "r")
 build_atomic_write(write_u32_atomic, "",  WORD, uint32_t, "r")
 build_atomic_write(write_int_atomic, "",  WORD, int, "r")
 
-#if 0 /* defined (CONFIG_ARM_64) */
-build_atomic_read(read_u64_atomic, "x", uint64_t, "=r")
-build_atomic_write(write_u64_atomic, "x", uint64_t, "r")
+#if defined (CONFIG_ARM_64)
+build_atomic_read(read_u64_atomic, "", "", uint64_t, "=r")
+build_atomic_write(write_u64_atomic, "", "", uint64_t, "r")
 #endif
 
 build_add_sized(add_u8_sized, "b", BYTE, uint8_t, "ri")
-- 
2.17.1
xsa295/4.8-03.patch (application/octet-stream, 3.7 KB)
From bd00fa1e050b005a64736285baeedbf5f778d4f2 Mon Sep 17 00:00:00 2001
From: Jan Beulich <[email protected]>
Date: Tue, 12 Mar 2019 14:40:56 +0100
Subject: [PATCH v2 4.8 03/21] common: avoid atomic read-modify-write accesses
 in map_vcpu_info()

There's no need to set the evtchn_pending_sel bits one by one. Simply
write full words with all ones.

For Arm this requires extending write_atomic() to also handle 64-bit
values; for symmetry read_atomic() gets adjusted as well.

Signed-off-by: Jan Beulich <[email protected]>
Reviewed-by: Andrew Cooper <[email protected]>
Reviewed-by: Julien Grall <[email protected]>
---
 xen/common/domain.c          |  9 ++++++---
 xen/include/asm-arm/atomic.h | 15 +++++++++++++++
 2 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/xen/common/domain.c b/xen/common/domain.c
index 314f880a92..740163ee77 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -1153,7 +1153,6 @@ int map_vcpu_info(struct vcpu *v, unsigned long gfn, unsigned offset)
     void *mapping;
     vcpu_info_t *new_info;
     struct page_info *page;
-    int i;
 
     if ( offset > (PAGE_SIZE - sizeof(vcpu_info_t)) )
         return -EINVAL;
@@ -1206,8 +1205,12 @@ int map_vcpu_info(struct vcpu *v, unsigned long gfn, unsigned offset)
      * Mark everything as being pending just to make sure nothing gets
      * lost.  The domain will get a spurious event, but it can cope.
      */
-    for ( i = 0; i < BITS_PER_EVTCHN_WORD(d); i++ )
-        set_bit(i, &vcpu_info(v, evtchn_pending_sel));
+#ifdef CONFIG_COMPAT
+    if ( !has_32bit_shinfo(d) )
+        write_atomic(&new_info->native.evtchn_pending_sel, ~0);
+    else
+#endif
+        write_atomic(&vcpu_info(v, evtchn_pending_sel), ~0);
     vcpu_mark_events_pending(v);
 
     return 0;
diff --git a/xen/include/asm-arm/atomic.h b/xen/include/asm-arm/atomic.h
index df9de6a74a..4bfa71356c 100644
--- a/xen/include/asm-arm/atomic.h
+++ b/xen/include/asm-arm/atomic.h
@@ -56,6 +56,19 @@ build_atomic_write(write_int_atomic, "",  WORD, int, "r")
 #if defined (CONFIG_ARM_64)
 build_atomic_read(read_u64_atomic, "", "", uint64_t, "=r")
 build_atomic_write(write_u64_atomic, "", "", uint64_t, "r")
+#elif defined (CONFIG_ARM_32)
+static inline uint64_t read_u64_atomic(const volatile uint64_t *addr)
+{
+    uint64_t val;
+
+    asm volatile ( "ldrd %0,%H0,%1" : "=r" (val) : "m" (*addr) );
+
+    return val;
+}
+static inline void write_u64_atomic(volatile uint64_t *addr, uint64_t val)
+{
+    asm volatile ( "strd %1,%H1,%0" : "=m" (*addr) : "r" (val) );
+}
 #endif
 
 build_add_sized(add_u8_sized, "b", BYTE, uint8_t, "ri")
@@ -70,6 +83,7 @@ void __bad_atomic_size(void);
     case 1: __x = (typeof(*p))read_u8_atomic((uint8_t *)p); break;      \
     case 2: __x = (typeof(*p))read_u16_atomic((uint16_t *)p); break;    \
     case 4: __x = (typeof(*p))read_u32_atomic((uint32_t *)p); break;    \
+    case 8: __x = (typeof(*p))read_u64_atomic((uint64_t *)p); break;    \
     default: __x = 0; __bad_atomic_size(); break;                       \
     }                                                                   \
     __x;                                                                \
@@ -81,6 +95,7 @@ void __bad_atomic_size(void);
     case 1: write_u8_atomic((uint8_t *)p, (uint8_t)__x); break;         \
     case 2: write_u16_atomic((uint16_t *)p, (uint16_t)__x); break;      \
     case 4: write_u32_atomic((uint32_t *)p, (uint32_t)__x); break;      \
+    case 8: write_u64_atomic((uint64_t *)p, (uint64_t)__x); break;      \
     default: __bad_atomic_size(); break;                                \
     }                                                                   \
     __x;                                                                \
-- 
2.17.1
xsa295/4.8-04.patch (application/octet-stream, 2.1 KB)
From 5c58b487fd37113408ef917522c3238a00a005b8 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:16 +0100
Subject: [PATCH v2 4.8 04/21] xen/arm: Add an isb() before reading CNTPCT_EL0
 to prevent re-ordering

Per D8.2.1 in ARM DDI 0487C.a, "a read to CNTPCT_EL0 can occur
speculatively and out of order relative to other instructions executed
on the same PE."

Add an instruction barrier to get accurate number of cycles when
requested in get_cycles(). For the other users of CNPCT_EL0, replace by
a call to get_cycles().

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Acked-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/time.c        | 4 ++--
 xen/include/asm-arm/time.h | 5 ++++-
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/time.c b/xen/arch/arm/time.c
index 7dae28bfd0..4a57eba942 100644
--- a/xen/arch/arm/time.c
+++ b/xen/arch/arm/time.c
@@ -151,7 +151,7 @@ void __init preinit_xen_time(void)
     if ( res )
         panic("Timer: Cannot initialize platform timer");
 
-    boot_count = READ_SYSREG64(CNTPCT_EL0);
+    boot_count = get_cycles();
 }
 
 static void __init init_dt_xen_time(void)
@@ -192,7 +192,7 @@ int __init init_xen_time(void)
 /* Return number of nanoseconds since boot */
 s_time_t get_s_time(void)
 {
-    uint64_t ticks = READ_SYSREG64(CNTPCT_EL0) - boot_count;
+    uint64_t ticks = get_cycles() - boot_count;
     return ticks_to_ns(ticks);
 }
 
diff --git a/xen/include/asm-arm/time.h b/xen/include/asm-arm/time.h
index 5b9a31de91..ca30406669 100644
--- a/xen/include/asm-arm/time.h
+++ b/xen/include/asm-arm/time.h
@@ -1,6 +1,8 @@
 #ifndef __ARM_TIME_H__
 #define __ARM_TIME_H__
 
+#include <asm/system.h>
+
 #define DT_MATCH_TIMER                      \
     DT_MATCH_COMPATIBLE("arm,armv7-timer"), \
     DT_MATCH_COMPATIBLE("arm,armv8-timer")
@@ -9,7 +11,8 @@ typedef unsigned long cycles_t;
 
 static inline cycles_t get_cycles (void)
 {
-        return 0;
+        isb();
+        return READ_SYSREG64(CNTPCT_EL0);
 }
 
 /* List of timer's IRQ */
-- 
2.17.1
xsa295/4.8-05.patch (application/octet-stream, 6.7 KB)
From 6eb7faeae9da73791f85b155a5d0713248077d42 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:17 +0100
Subject: [PATCH v2 4.8 05/21] xen/grant_table: Rework the prototype of
 _set_status* for lisibility

It is not clear from the parameters name whether domid and gt_version
correspond to the local or remote domain. A follow-up patch will make
them more confusing.

So rename domid (resp. gt_version) to ldomid (resp. rgt_version). At
the same time re-order the parameters to hopefully make it more
readable.

This is part of XSA-295.

Suggested-by: Jan Beulich <[email protected]>
Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Jan Beulich <[email protected]>
Acked-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/common/grant_table.c | 57 ++++++++++++++++++++--------------------
 1 file changed, 28 insertions(+), 29 deletions(-)

diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index 03fe38acb5..a555dabbf7 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -545,11 +545,11 @@ static unsigned int nr_grant_entries(struct grant_table *gt)
     return 0;
 }
 
-static int _set_status_v1(domid_t  domid,
+static int _set_status_v1(const grant_entry_header_t *shah,
+                          struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
-                          grant_entry_header_t *shah, 
-                          struct active_grant_entry *act)
+                          domid_t  ldomid)
 {
     int rc = GNTST_okay;
     union grant_combo scombo, prev_scombo, new_scombo;
@@ -584,11 +584,11 @@ static int _set_status_v1(domid_t  domid,
         if ( !act->pin &&
              (((scombo.shorts.flags & mask) !=
                GTF_permit_access) ||
-              (scombo.shorts.domid != domid)) )
+              (scombo.shorts.domid != ldomid)) )
             PIN_FAIL(done, GNTST_general_error,
                      "Bad flags (%x) or dom (%d). (expected dom %d)\n",
                      scombo.shorts.flags, scombo.shorts.domid,
-                     domid);
+                     ldomid);
 
         new_scombo = scombo;
         new_scombo.shorts.flags |= GTF_reading;
@@ -617,12 +617,12 @@ done:
     return rc;
 }
 
-static int _set_status_v2(domid_t  domid,
+static int _set_status_v2(const grant_entry_header_t *shah,
+                          grant_status_t *status,
+                          struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
-                          grant_entry_header_t *shah, 
-                          struct active_grant_entry *act,
-                          grant_status_t *status)
+                          domid_t  ldomid)
 {
     int      rc    = GNTST_okay;
     union grant_combo scombo;
@@ -648,10 +648,10 @@ static int _set_status_v2(domid_t  domid,
     if ( !act->pin &&
          ( (((flags & mask) != GTF_permit_access) &&
             ((flags & mask) != GTF_transitive)) ||
-          (id != domid)) )
+          (id != ldomid)) )
         PIN_FAIL(done, GNTST_general_error,
                  "Bad flags (%x) or dom (%d). (expected dom %d, flags %x)\n",
-                 flags, id, domid, mask);
+                 flags, id, ldomid, mask);
 
     if ( readonly )
     {
@@ -678,7 +678,7 @@ static int _set_status_v2(domid_t  domid,
     {
         if ( (((flags & mask) != GTF_permit_access) &&
               ((flags & mask) != GTF_transitive)) ||
-             (id != domid) ||
+             (id != ldomid) ||
              (!readonly && (flags & GTF_readonly)) )
         {
             gnttab_clear_flag(_GTF_writing, status);
@@ -686,7 +686,7 @@ static int _set_status_v2(domid_t  domid,
             PIN_FAIL(done, GNTST_general_error,
                      "Unstable flags (%x) or dom (%d). (expected dom %d) "
                      "(r/w: %d)\n",
-                     flags, id, domid, !readonly);
+                     flags, id, ldomid, !readonly);
         }
     }
     else
@@ -704,19 +704,19 @@ done:
 }
 
 
-static int _set_status(unsigned gt_version,
-                       domid_t  domid,
+static int _set_status(const grant_entry_header_t *shah,
+                       grant_status_t *status,
+                       unsigned rgt_version,
+                       struct active_grant_entry *act,
                        int readonly,
                        int mapflag,
-                       grant_entry_header_t *shah,
-                       struct active_grant_entry *act,
-                       grant_status_t *status)
+                       domid_t ldomid)
 {
 
-    if (gt_version == 1)
-        return _set_status_v1(domid, readonly, mapflag, shah, act);
+    if ( rgt_version == 1 )
+        return _set_status_v1(shah, act, readonly, mapflag, ldomid);
     else
-        return _set_status_v2(domid, readonly, mapflag, shah, act, status);
+        return _set_status_v2(shah, status, act, readonly, mapflag, ldomid);
 }
 
 static struct active_grant_entry *grant_map_exists(const struct domain *ld,
@@ -884,9 +884,9 @@ __gnttab_map_grant_ref(
          (!(op->flags & GNTMAP_readonly) &&
           !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask))) )
     {
-        if ( (rc = _set_status(rgt->gt_version, ld->domain_id,
-                               op->flags & GNTMAP_readonly,
-                               1, shah, act, status) ) != GNTST_okay )
+        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+                               op->flags & GNTMAP_readonly, 1,
+                               ld->domain_id) != GNTST_okay) )
             goto act_release_out;
 
         if ( !act->pin )
@@ -2258,8 +2258,8 @@ __acquire_grant_for_copy(
     {
         if ( (!old_pin || (!readonly &&
                            !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)))) &&
-             (rc = _set_status_v2(ldom, readonly, 0, shah, act,
-                                  status)) != GNTST_okay )
+             (rc = _set_status_v2(shah, status, act, readonly, 0,
+                                  ldom)) != GNTST_okay )
             goto unlock_out;
 
         if ( !allow_transitive )
@@ -2357,9 +2357,8 @@ __acquire_grant_for_copy(
     else if ( !old_pin ||
               (!readonly && !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask))) )
     {
-        if ( (rc = _set_status(rgt->gt_version, ldom,
-                               readonly, 0, shah, act,
-                               status) ) != GNTST_okay )
+        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+                               readonly, 0, ldom)) != GNTST_okay )
              goto unlock_out;
 
         td = rd;
-- 
2.17.1
xsa295/4.8-06.patch (application/octet-stream, 7.8 KB)
From 40be7202ee6cfb5902a2dbef099396c848e2051c Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:18 +0100
Subject: [PATCH v2 4.8 06/21] xen/arm64: bitops: Rewrite bitop helpers in C

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/README.LinuxPrimitives |  1 -
 xen/arch/arm/arm64/lib/bitops.S     | 69 ----------------------
 xen/arch/arm/arm64/lib/bitops.c     | 90 +++++++++++++++++++++++++++++
 3 files changed, 90 insertions(+), 70 deletions(-)
 delete mode 100644 xen/arch/arm/arm64/lib/bitops.S
 create mode 100644 xen/arch/arm/arm64/lib/bitops.c

diff --git a/xen/arch/arm/README.LinuxPrimitives b/xen/arch/arm/README.LinuxPrimitives
index 028e8721f9..891667a5da 100644
--- a/xen/arch/arm/README.LinuxPrimitives
+++ b/xen/arch/arm/README.LinuxPrimitives
@@ -8,7 +8,6 @@ arm64:
 
 bitops: last sync @ v3.16-rc6 (last commit: 8715466b6027)
 
-linux/arch/arm64/lib/bitops.S           xen/arch/arm/arm64/lib/bitops.S
 linux/arch/arm64/include/asm/bitops.h   xen/include/asm-arm/arm64/bitops.h
 
 ---------------------------------------------------------------------
diff --git a/xen/arch/arm/arm64/lib/bitops.S b/xen/arch/arm/arm64/lib/bitops.S
deleted file mode 100644
index e1ad2398ef..0000000000
--- a/xen/arch/arm/arm64/lib/bitops.S
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Based on linux/arch/arm64/lib/bitops.h which in turn is
- * Based on arch/arm/lib/bitops.h
- *
- * Copyright (C) 2013 ARM Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <xen/config.h>
-
-/*
- * x0: bits 4:0  bit offset
- *     bits 31:5 word offset
- * x1: address
- */
-	.macro	bitop, name, instr
-ENTRY(	\name	)
-	and	w3, w0, #31		// Get bit offset
-	eor	w0, w0, w3		// Clear low bits
-	mov	x2, #1
-	add	x1, x1, x0, lsr #3	// Get word offset
-	lsl	x3, x2, x3		// Create mask
-1:	ldxr	w2, [x1]
-	\instr	w2, w2, w3
-	stxr	w0, w2, [x1]
-	cbnz	w0, 1b
-	ret
-ENDPROC(\name	)
-	.endm
-
-	.macro	testop, name, instr
-ENTRY(	\name	)
-	and	w3, w0, #31		// Get bit offset
-	eor	w0, w0, w3		// Clear low bits
-	mov	x2, #1
-	add	x1, x1, x0, lsr #3	// Get word offset
-	lsl	x4, x2, x3		// Create mask
-1:	ldxr	w2, [x1]
-	lsr	w0, w2, w3		// Save old value of bit
-	\instr	w2, w2, w4		// toggle bit
-	stlxr	w5, w2, [x1]
-	cbnz	w5, 1b
-	dmb	ish
-	and	w0, w0, #1
-3:	ret
-ENDPROC(\name	)
-	.endm
-
-/*
- * Atomic bit operations.
- */
-	bitop	change_bit, eor
-	bitop	clear_bit, bic
-	bitop	set_bit, orr
-
-	testop	test_and_change_bit, eor
-	testop	test_and_clear_bit, bic
-	testop	test_and_set_bit, orr
diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
new file mode 100644
index 0000000000..b1c681c642
--- /dev/null
+++ b/xen/arch/arm/arm64/lib/bitops.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/bitops.h>
+#include <asm/system.h>
+
+/*
+ * The atomic bit operations pass the number of bit in a signed number
+ * (not sure why). This has the drawback to increase the complexity of
+ * the resulting assembly.
+ *
+ * To generate simpler code, the number of bit (nr) will be cast to
+ * unsigned int.
+ *
+ * XXX: Rework the interface to use unsigned int.
+ */
+
+#define bitop(name, instr)                                                  \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
+    unsigned long res, tmp;                                                 \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldxr    %w2, %1\n"                                              \
+        "   " __stringify(instr) "     %w2, %w2, %w3\n"                     \
+        "   stxr    %w0, %w2, %1\n"                                         \
+        : "=&r" (res), "+Q" (*ptr), "=&r" (tmp)                             \
+        : "r" (mask));                                                      \
+    } while ( res );                                                        \
+}                                                                           \
+
+#define testop(name, instr)                                                 \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
+    const uint32_t mask = BIT_MASK(bit);                                    \
+    unsigned long res, tmp;                                                 \
+    unsigned long oldbit;                                                   \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldxr    %w3, %2\n"                                              \
+        "   lsr     %w1, %w3, %w5 // Save old value of bit\n"               \
+        "   " __stringify(instr) "  %w3, %w3, %w4 // Toggle bit\n"          \
+        "   stlxr   %w0, %w3, %2\n"                                         \
+        : "=&r" (res), "=&r" (oldbit), "+Q" (*ptr), "=&r" (tmp)             \
+        : "r" (mask), "r" (bit)                                             \
+        : "memory");                                                        \
+    } while ( res );                                                        \
+                                                                            \
+    dmb(ish);                                                               \
+                                                                            \
+    return oldbit & 1;                                                      \
+}
+
+bitop(change_bit, eor)
+bitop(clear_bit, bic)
+bitop(set_bit, orr)
+
+testop(test_and_change_bit, eor)
+testop(test_and_clear_bit, bic)
+testop(test_and_set_bit, orr)
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.17.1
xsa295/4.8-07.patch (application/octet-stream, 15.7 KB)
From 9061ba6c0561764e9c7f8aa043b2854963a92086 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:19 +0100
Subject: [PATCH v2 4.8 07/21] xen/arm32: bitops: Rewrite bitop helpers in C

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/README.LinuxPrimitives    |  14 +---
 xen/arch/arm/arm32/lib/Makefile        |   5 +-
 xen/arch/arm/arm32/lib/bitops.c        |  98 +++++++++++++++++++++++
 xen/arch/arm/arm32/lib/bitops.h        | 105 -------------------------
 xen/arch/arm/arm32/lib/changebit.S     |  16 ----
 xen/arch/arm/arm32/lib/clearbit.S      |  17 ----
 xen/arch/arm/arm32/lib/setbit.S        |  16 ----
 xen/arch/arm/arm32/lib/testchangebit.S |  16 ----
 xen/arch/arm/arm32/lib/testclearbit.S  |  16 ----
 xen/arch/arm/arm32/lib/testsetbit.S    |  16 ----
 xen/include/asm-arm/arm32/bitops.h     |  19 ++---
 11 files changed, 108 insertions(+), 230 deletions(-)
 create mode 100644 xen/arch/arm/arm32/lib/bitops.c
 delete mode 100644 xen/arch/arm/arm32/lib/bitops.h
 delete mode 100644 xen/arch/arm/arm32/lib/changebit.S
 delete mode 100644 xen/arch/arm/arm32/lib/clearbit.S
 delete mode 100644 xen/arch/arm/arm32/lib/setbit.S
 delete mode 100644 xen/arch/arm/arm32/lib/testchangebit.S
 delete mode 100644 xen/arch/arm/arm32/lib/testclearbit.S
 delete mode 100644 xen/arch/arm/arm32/lib/testsetbit.S

diff --git a/xen/arch/arm/README.LinuxPrimitives b/xen/arch/arm/README.LinuxPrimitives
index 891667a5da..664a9f89ed 100644
--- a/xen/arch/arm/README.LinuxPrimitives
+++ b/xen/arch/arm/README.LinuxPrimitives
@@ -68,19 +68,9 @@ arm32
 
 bitops: last sync @ v3.16-rc6 (last commit: c32ffce0f66e)
 
-linux/arch/arm/lib/bitops.h             xen/arch/arm/arm32/lib/bitops.h
-linux/arch/arm/lib/changebit.S          xen/arch/arm/arm32/lib/changebit.S
-linux/arch/arm/lib/clearbit.S           xen/arch/arm/arm32/lib/clearbit.S
 linux/arch/arm/lib/findbit.S            xen/arch/arm/arm32/lib/findbit.S
-linux/arch/arm/lib/setbit.S             xen/arch/arm/arm32/lib/setbit.S
-linux/arch/arm/lib/testchangebit.S      xen/arch/arm/arm32/lib/testchangebit.S
-linux/arch/arm/lib/testclearbit.S       xen/arch/arm/arm32/lib/testclearbit.S
-linux/arch/arm/lib/testsetbit.S         xen/arch/arm/arm32/lib/testsetbit.S
-
-for i in bitops.h changebit.S clearbit.S findbit.S setbit.S testchangebit.S \
-         testclearbit.S testsetbit.S; do
-    diff -u ../linux/arch/arm/lib/$i xen/arch/arm/arm32/lib/$i;
-done
+
+diff -u ../linux/arch/arm/lib/findbit.S xen/arch/arm/arm32/lib/findbit.S
 
 ---------------------------------------------------------------------
 
diff --git a/xen/arch/arm/arm32/lib/Makefile b/xen/arch/arm/arm32/lib/Makefile
index e9fbc595b9..b1457c89dc 100644
--- a/xen/arch/arm/arm32/lib/Makefile
+++ b/xen/arch/arm/arm32/lib/Makefile
@@ -1,6 +1,5 @@
 obj-y += memcpy.o memmove.o memset.o memchr.o memzero.o
-obj-y += findbit.o setbit.o
-obj-y += setbit.o clearbit.o changebit.o
-obj-y += testsetbit.o testclearbit.o testchangebit.o
+obj-y += findbit.o
+obj-y += bitops.o
 obj-y += strchr.o strrchr.o
 obj-y += lib1funcs.o lshrdi3.o div64.o
diff --git a/xen/arch/arm/arm32/lib/bitops.c b/xen/arch/arm/arm32/lib/bitops.c
new file mode 100644
index 0000000000..c69bb53037
--- /dev/null
+++ b/xen/arch/arm/arm32/lib/bitops.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/bitops.h>
+#include <xen/prefetch.h>
+#include <asm/system.h>
+
+/*
+ * The atomic bit operations pass the number of bit in a signed number
+ * (not sure why). This has the drawback to increase the complexity of
+ * the resulting assembly.
+ *
+ * To generate simpler code, the number of bit (nr) will be cast to
+ * unsigned int.
+ *
+ * XXX: Rework the interface to use unsigned int.
+ */
+
+#define bitop(name, instr)                                                  \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
+    unsigned long res, tmp;                                                 \
+                                                                            \
+    ASSERT(((vaddr_t)p & 0x3) == 0);                                        \
+    prefetchw((const void *)ptr);                                           \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldrex   %2, %1\n"                                               \
+        "   " __stringify(instr) "     %2, %2, %3\n"                        \
+        "   strex   %0, %2, %1\n"                                           \
+        : "=&r" (res), "+Qo" (*ptr), "=&r" (tmp)                            \
+        : "r" (mask));                                                      \
+    } while ( res );                                                        \
+}
+
+#define testop(name, instr)                                                 \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
+    const uint32_t mask = BIT_MASK(bit);                                    \
+    unsigned long res, tmp;                                                 \
+    int oldbit;                                                             \
+                                                                            \
+    ASSERT(((vaddr_t)p & 0x3) == 0);                                        \
+    smp_mb();                                                               \
+                                                                            \
+    prefetchw((const void *)ptr);                                           \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldrex   %3, %2\n"                                               \
+        "   lsr     %1, %3, %5 // Save old value of bit\n"                  \
+        "   " __stringify(instr) "  %3, %3, %4 // Toggle bit\n"             \
+        "   strex  %0, %3, %2\n"                                            \
+        : "=&r" (res), "=&r" (oldbit), "+Qo" (*ptr), "=&r" (tmp)            \
+        : "r" (mask), "r" (bit));                                           \
+    } while ( res );                                                        \
+                                                                            \
+    smp_mb();                                                               \
+                                                                            \
+    return oldbit & 1;                                                      \
+}                                                                           \
+
+bitop(change_bit, eor)
+bitop(clear_bit, bic)
+bitop(set_bit, orr)
+
+testop(test_and_change_bit, eor)
+testop(test_and_clear_bit, bic)
+testop(test_and_set_bit, orr)
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/arm32/lib/bitops.h b/xen/arch/arm/arm32/lib/bitops.h
deleted file mode 100644
index a167c2d436..0000000000
--- a/xen/arch/arm/arm32/lib/bitops.h
+++ /dev/null
@@ -1,105 +0,0 @@
-#include <xen/config.h>
-
-#if __LINUX_ARM_ARCH__ >= 6
-	.macro	bitop, name, instr
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	mov	r2, #1
-	and	r3, r0, #31		@ Get bit offset
-	mov	r0, r0, lsr #5
-	add	r1, r1, r0, lsl #2	@ Get word offset
-#if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
-	.arch_extension	mp
-	ALT_SMP(W(pldw)	[r1])
-	ALT_UP(W(nop))
-#endif
-	mov	r3, r2, lsl r3
-1:	ldrex	r2, [r1]
-	\instr	r2, r2, r3
-	strex	r0, r2, [r1]
-	cmp	r0, #0
-	bne	1b
-	bx	lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-
-	.macro	testop, name, instr, store
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	mov	r2, #1
-	and	r3, r0, #31		@ Get bit offset
-	mov	r0, r0, lsr #5
-	add	r1, r1, r0, lsl #2	@ Get word offset
-	mov	r3, r2, lsl r3		@ create mask
-	smp_dmb
-#if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
-	.arch_extension	mp
-	ALT_SMP(W(pldw)	[r1])
-	ALT_UP(W(nop))
-#endif
-1:	ldrex	r2, [r1]
-	ands	r0, r2, r3		@ save old value of bit
-	\instr	r2, r2, r3		@ toggle bit
-	strex	ip, r2, [r1]
-	cmp	ip, #0
-	bne	1b
-	smp_dmb
-	cmp	r0, #0
-	movne	r0, #1
-2:	bx	lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-#else
-	.macro	bitop, name, instr
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	and	r2, r0, #31
-	mov	r0, r0, lsr #5
-	mov	r3, #1
-	mov	r3, r3, lsl r2
-	save_and_disable_irqs ip
-	ldr	r2, [r1, r0, lsl #2]
-	\instr	r2, r2, r3
-	str	r2, [r1, r0, lsl #2]
-	restore_irqs ip
-	mov	pc, lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-
-/**
- * testop - implement a test_and_xxx_bit operation.
- * @instr: operational instruction
- * @store: store instruction
- *
- * Note: we can trivially conditionalise the store instruction
- * to avoid dirtying the data cache.
- */
-	.macro	testop, name, instr, store
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	and	r3, r0, #31
-	mov	r0, r0, lsr #5
-	save_and_disable_irqs ip
-	ldr	r2, [r1, r0, lsl #2]!
-	mov	r0, #1
-	tst	r2, r0, lsl r3
-	\instr	r2, r2, r0, lsl r3
-	\store	r2, [r1]
-	moveq	r0, #0
-	restore_irqs ip
-	mov	pc, lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-#endif
diff --git a/xen/arch/arm/arm32/lib/changebit.S b/xen/arch/arm/arm32/lib/changebit.S
deleted file mode 100644
index 11f41d2bd6..0000000000
--- a/xen/arch/arm/arm32/lib/changebit.S
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- *  linux/arch/arm/lib/changebit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <xen/config.h>
-
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-bitop	_change_bit, eor
diff --git a/xen/arch/arm/arm32/lib/clearbit.S b/xen/arch/arm/arm32/lib/clearbit.S
deleted file mode 100644
index 1b6a5691f8..0000000000
--- a/xen/arch/arm/arm32/lib/clearbit.S
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- *  linux/arch/arm/lib/clearbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <xen/config.h>
-
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-bitop	_clear_bit, bic
diff --git a/xen/arch/arm/arm32/lib/setbit.S b/xen/arch/arm/arm32/lib/setbit.S
deleted file mode 100644
index 1f4ef5659b..0000000000
--- a/xen/arch/arm/arm32/lib/setbit.S
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- *  linux/arch/arm/lib/setbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <xen/config.h>
-
-#include "assembler.h"
-#include "bitops.h"
-	.text
-
-bitop	_set_bit, orr
diff --git a/xen/arch/arm/arm32/lib/testchangebit.S b/xen/arch/arm/arm32/lib/testchangebit.S
deleted file mode 100644
index 7f4635caa2..0000000000
--- a/xen/arch/arm/arm32/lib/testchangebit.S
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- *  linux/arch/arm/lib/testchangebit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <xen/config.h>
-
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-testop	_test_and_change_bit, eor, str
diff --git a/xen/arch/arm/arm32/lib/testclearbit.S b/xen/arch/arm/arm32/lib/testclearbit.S
deleted file mode 100644
index 4d4152fda8..0000000000
--- a/xen/arch/arm/arm32/lib/testclearbit.S
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- *  linux/arch/arm/lib/testclearbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <xen/config.h>
-
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-testop	_test_and_clear_bit, bicne, strne
diff --git a/xen/arch/arm/arm32/lib/testsetbit.S b/xen/arch/arm/arm32/lib/testsetbit.S
deleted file mode 100644
index 54f48f9afa..0000000000
--- a/xen/arch/arm/arm32/lib/testsetbit.S
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- *  linux/arch/arm/lib/testsetbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <xen/config.h>
-
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-testop	_test_and_set_bit, orreq, streq
diff --git a/xen/include/asm-arm/arm32/bitops.h b/xen/include/asm-arm/arm32/bitops.h
index 8be3564540..67c4c3f55c 100644
--- a/xen/include/asm-arm/arm32/bitops.h
+++ b/xen/include/asm-arm/arm32/bitops.h
@@ -1,19 +1,12 @@
 #ifndef _ARM_ARM32_BITOPS_H
 #define _ARM_ARM32_BITOPS_H
 
-extern void _set_bit(int nr, volatile void * p);
-extern void _clear_bit(int nr, volatile void * p);
-extern void _change_bit(int nr, volatile void * p);
-extern int _test_and_set_bit(int nr, volatile void * p);
-extern int _test_and_clear_bit(int nr, volatile void * p);
-extern int _test_and_change_bit(int nr, volatile void * p);
-
-#define set_bit(n,p)              _set_bit(n,p)
-#define clear_bit(n,p)            _clear_bit(n,p)
-#define change_bit(n,p)           _change_bit(n,p)
-#define test_and_set_bit(n,p)     _test_and_set_bit(n,p)
-#define test_and_clear_bit(n,p)   _test_and_clear_bit(n,p)
-#define test_and_change_bit(n,p)  _test_and_change_bit(n,p)
+extern void set_bit(int nr, volatile void * p);
+extern void clear_bit(int nr, volatile void * p);
+extern void change_bit(int nr, volatile void * p);
+extern int test_and_set_bit(int nr, volatile void * p);
+extern int test_and_clear_bit(int nr, volatile void * p);
+extern int test_and_change_bit(int nr, volatile void * p);
 
 #define flsl fls
 
-- 
2.17.1
xsa295/4.8-08.patch (application/octet-stream, 2.7 KB)
From a1db9cab327b511753a42ba3d055f3631999e065 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:20 +0100
Subject: [PATCH v2 4.8 08/21] xen/arm: bitops: Consolidate prototypes in one
 place

The prototype are the same between arm32 and arm64. Consolidate them in
asm-arm/bitops.h.

This change will help the introductions of new helpers in a follow-up
patch.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm32/bitops.h |  7 -------
 xen/include/asm-arm/arm64/bitops.h | 10 ----------
 xen/include/asm-arm/bitops.h       |  8 ++++++++
 3 files changed, 8 insertions(+), 17 deletions(-)

diff --git a/xen/include/asm-arm/arm32/bitops.h b/xen/include/asm-arm/arm32/bitops.h
index 67c4c3f55c..57938a5874 100644
--- a/xen/include/asm-arm/arm32/bitops.h
+++ b/xen/include/asm-arm/arm32/bitops.h
@@ -1,13 +1,6 @@
 #ifndef _ARM_ARM32_BITOPS_H
 #define _ARM_ARM32_BITOPS_H
 
-extern void set_bit(int nr, volatile void * p);
-extern void clear_bit(int nr, volatile void * p);
-extern void change_bit(int nr, volatile void * p);
-extern int test_and_set_bit(int nr, volatile void * p);
-extern int test_and_clear_bit(int nr, volatile void * p);
-extern int test_and_change_bit(int nr, volatile void * p);
-
 #define flsl fls
 
 /*
diff --git a/xen/include/asm-arm/arm64/bitops.h b/xen/include/asm-arm/arm64/bitops.h
index 6bf1922680..6cc224ad13 100644
--- a/xen/include/asm-arm/arm64/bitops.h
+++ b/xen/include/asm-arm/arm64/bitops.h
@@ -1,16 +1,6 @@
 #ifndef _ARM_ARM64_BITOPS_H
 #define _ARM_ARM64_BITOPS_H
 
-/*
- * Little endian assembly atomic bitops.
- */
-extern void set_bit(int nr, volatile void *p);
-extern void clear_bit(int nr, volatile void *p);
-extern void change_bit(int nr, volatile void *p);
-extern int test_and_set_bit(int nr, volatile void *p);
-extern int test_and_clear_bit(int nr, volatile void *p);
-extern int test_and_change_bit(int nr, volatile void *p);
-
 /* Based on linux/include/asm-generic/bitops/builtin-__ffs.h */
 /**
  * __ffs - find first bit in word.
diff --git a/xen/include/asm-arm/bitops.h b/xen/include/asm-arm/bitops.h
index bda889841b..8e864b4456 100644
--- a/xen/include/asm-arm/bitops.h
+++ b/xen/include/asm-arm/bitops.h
@@ -37,6 +37,14 @@
 # error "unknown ARM variant"
 #endif
 
+/* Atomics bitops */
+void set_bit(int nr, volatile void *p);
+void clear_bit(int nr, volatile void *p);
+void change_bit(int nr, volatile void *p);
+int test_and_set_bit(int nr, volatile void *p);
+int test_and_clear_bit(int nr, volatile void *p);
+int test_and_change_bit(int nr, volatile void *p);
+
 /**
  * __test_and_set_bit - Set a bit and return its old value
  * @nr: Bit to set
-- 
2.17.1
xsa295/4.8-09.patch (application/octet-stream, 3.7 KB)
From 9577870b8ef7875f82e8ea656555c03f8f9d5891 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Wed, 22 May 2019 13:37:53 -0700
Subject: [PATCH v2 4.8 09/21] xen/arm64: cmpxchg: Simplify the cmpxchg
 implementation

The only difference between each case of the cmpxchg is the size of
used. Rather than duplicating the code, provide a macro to generate each
cases.

This makes the code easier to read and modify.

This is part of XSA-295.

Signed-off-by; Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm64/cmpxchg.h | 98 +++++++++++------------------
 1 file changed, 36 insertions(+), 62 deletions(-)

diff --git a/xen/include/asm-arm/arm64/cmpxchg.h b/xen/include/asm-arm/arm64/cmpxchg.h
index ae42b2f5ff..393fbca6a5 100644
--- a/xen/include/asm-arm/arm64/cmpxchg.h
+++ b/xen/include/asm-arm/arm64/cmpxchg.h
@@ -61,80 +61,54 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
 	__ret; \
 })
 
-extern void __bad_cmpxchg(volatile void *ptr, int size);
+extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
+
+#define __CMPXCHG_CASE(w, sz, name)					\
+static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
+						  unsigned long old,	\
+						  unsigned long new)	\
+{									\
+	unsigned long res, oldval;					\
+									\
+	do {								\
+		asm volatile("// __cmpxchg_case_" #name "\n"		\
+		"	ldxr" #sz "	%" #w "1, %2\n"			\
+		"	mov	%w0, #0\n"				\
+		"	cmp	%" #w "1, %" #w "3\n"			\
+		"	b.ne	1f\n"					\
+		"	stxr" #sz "	%w0, %" #w "4, %2\n"		\
+		"1:\n"							\
+		: "=&r" (res), "=&r" (oldval),				\
+		  "+Q" (*(unsigned long *)ptr)				\
+		: "Ir" (old), "r" (new)					\
+		: "cc");						\
+	} while (res);							\
+									\
+	return oldval;							\
+}
+
+__CMPXCHG_CASE(w, b, 1)
+__CMPXCHG_CASE(w, h, 2)
+__CMPXCHG_CASE(w,  , 4)
+__CMPXCHG_CASE( ,  , 8)
 
 static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 				      unsigned long new, int size)
 {
-	unsigned long oldval = 0, res;
-
 	switch (size) {
 	case 1:
-		do {
-			asm volatile("// __cmpxchg1\n"
-			"	ldxrb	%w1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%w1, %w3\n"
-			"	b.ne	1f\n"
-			"	stxrb	%w0, %w4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u8 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_1(ptr, old, new);
 	case 2:
-		do {
-			asm volatile("// __cmpxchg2\n"
-			"	ldxrh	%w1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%w1, %w3\n"
-			"	b.ne	1f\n"
-			"	stxrh	%w0, %w4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u16 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_2(ptr, old, new);
 	case 4:
-		do {
-			asm volatile("// __cmpxchg4\n"
-			"	ldxr	%w1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%w1, %w3\n"
-			"	b.ne	1f\n"
-			"	stxr	%w0, %w4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u32 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_4(ptr, old, new);
 	case 8:
-		do {
-			asm volatile("// __cmpxchg8\n"
-			"	ldxr	%1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%1, %3\n"
-			"	b.ne	1f\n"
-			"	stxr	%w0, %4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u64 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_8(ptr, old, new);
 	default:
-		__bad_cmpxchg(ptr, size);
-		oldval = 0;
+		return __bad_cmpxchg(ptr, size);
 	}
 
-	return oldval;
+	ASSERT_UNREACHABLE();
 }
 
 static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
-- 
2.17.1
xsa295/4.8-10.patch (application/octet-stream, 3.6 KB)
From 8f3a9a515612644692eef25f6231239ada269121 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:22 +0100
Subject: [PATCH v2 4.8 10/21] xen/arm32: cmpxchg: Simplify the cmpxchg
 implementation

The only difference between each case of the cmpxchg is the size of
used. Rather than duplicating the code, provide a macro to generate each
cases.

This makes the code easier to read and modify.

While doing the rework, the case for 64-bit cmpxchg is removed. This is
unused today (already commented) and it would not be possible to use
it directly.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm32/cmpxchg.h | 84 +++++++++++------------------
 1 file changed, 31 insertions(+), 53 deletions(-)

diff --git a/xen/include/asm-arm/arm32/cmpxchg.h b/xen/include/asm-arm/arm32/cmpxchg.h
index 03e0bed3a6..471a9e3a3f 100644
--- a/xen/include/asm-arm/arm32/cmpxchg.h
+++ b/xen/include/asm-arm/arm32/cmpxchg.h
@@ -52,72 +52,50 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
  * indicated by comparing RETURN with OLD.
  */
 
-extern void __bad_cmpxchg(volatile void *ptr, int size);
+extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
+
+#define __CMPXCHG_CASE(sz, name)					\
+static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
+						  unsigned long old,	\
+						  unsigned long new)	\
+{									\
+	unsigned long oldval, res;					\
+									\
+	do {								\
+		asm volatile("@ __cmpxchg_case_" #name "\n"		\
+		"	ldrex" #sz "	%1, [%2]\n"			\
+		"	mov	%0, #0\n"				\
+		"	teq	%1, %3\n"				\
+		"	strex" #sz "eq %0, %4, [%2]\n"			\
+		: "=&r" (res), "=&r" (oldval)				\
+		: "r" (ptr), "Ir" (old), "r" (new)			\
+		: "memory", "cc");					\
+	} while (res);							\
+									\
+	return oldval;							\
+}
+
+__CMPXCHG_CASE(b, 1)
+__CMPXCHG_CASE(h, 2)
+__CMPXCHG_CASE( , 4)
 
 static always_inline unsigned long __cmpxchg(
     volatile void *ptr, unsigned long old, unsigned long new, int size)
 {
-	unsigned long oldval, res;
-
 	prefetchw((const void *)ptr);
 
 	switch (size) {
 	case 1:
-		do {
-			asm volatile("@ __cmpxchg1\n"
-			"	ldrexb	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexbeq %0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-		} while (res);
-		break;
+		return __cmpxchg_case_1(ptr, old, new);
 	case 2:
-		do {
-			asm volatile("@ __cmpxchg2\n"
-			"	ldrexh	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexheq %0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-		} while (res);
-		break;
+		return __cmpxchg_case_2(ptr, old, new);
 	case 4:
-		do {
-			asm volatile("@ __cmpxchg4\n"
-			"	ldrex	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexeq	%0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-	    } while (res);
-	    break;
-#if 0
-	case 8:
-		do {
-			asm volatile("@ __cmpxchg8\n"
-			"	ldrexd	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexdeq %0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-		} while (res);
-		break;
-#endif
+		return __cmpxchg_case_4(ptr, old, new);
 	default:
-		__bad_cmpxchg(ptr, size);
-		oldval = 0;
+		return __bad_cmpxchg(ptr, size);
 	}
 
-	return oldval;
+	ASSERT_UNREACHABLE();
 }
 
 static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
-- 
2.17.1
xsa295/4.8-11.patch (application/octet-stream, 15.3 KB)
From 3dbcc94eed25cd30f0f981e82f6ae6b9430f4cc9 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:23 +0100
Subject: [PATCH v2 4.8 11/21] xen/arm: bitops: Implement a new set of helpers
 that can timeout

Exclusive load-store atomics should only be used between trusted
threads. As not all the guests are trusted, it may be possible to DoS
Xen when updating shared memory with guest atomically.

To prevent the infinite loop, we introduce a new set of helpers that can
timeout. The timeout is based on the maximum number of iterations.

They will be used in follow-up patch to make atomic operations
on shared memory safe.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/arm32/lib/bitops.c | 52 ++++++++++++++++++++++++++++-----
 xen/arch/arm/arm64/lib/bitops.c | 52 ++++++++++++++++++++++++++++-----
 xen/include/asm-arm/bitops.h    | 28 +++++++++++++++++-
 3 files changed, 117 insertions(+), 15 deletions(-)

diff --git a/xen/arch/arm/arm32/lib/bitops.c b/xen/arch/arm/arm32/lib/bitops.c
index c69bb53037..08750314fc 100644
--- a/xen/arch/arm/arm32/lib/bitops.c
+++ b/xen/arch/arm/arm32/lib/bitops.c
@@ -30,7 +30,8 @@
  */
 
 #define bitop(name, instr)                                                  \
-void name(int nr, volatile void *p)                                         \
+static always_inline bool int_##name(int nr, volatile void *p, bool timeout,\
+                                     unsigned int max_try)                  \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
@@ -47,17 +48,33 @@ void name(int nr, volatile void *p)                                         \
         "   strex   %0, %2, %1\n"                                           \
         : "=&r" (res), "+Qo" (*ptr), "=&r" (tmp)                            \
         : "r" (mask));                                                      \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
+                                                                            \
+    return !res;                                                            \
+}                                                                           \
+                                                                            \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    if ( !int_##name(nr, p, false, 0) )                                     \
+        ASSERT_UNREACHABLE();                                               \
+}                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p, unsigned int max_try)         \
+{                                                                           \
+    return int_##name(nr, p, true, max_try);                                \
 }
 
 #define testop(name, instr)                                                 \
-int name(int nr, volatile void *p)                                          \
+static always_inline bool int_##name(int nr, volatile void *p, int *oldbit, \
+                                     bool timeout, unsigned int max_try)    \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
     const uint32_t mask = BIT_MASK(bit);                                    \
     unsigned long res, tmp;                                                 \
-    int oldbit;                                                             \
                                                                             \
     ASSERT(((vaddr_t)p & 0x3) == 0);                                        \
     smp_mb();                                                               \
@@ -71,14 +88,35 @@ int name(int nr, volatile void *p)                                          \
         "   lsr     %1, %3, %5 // Save old value of bit\n"                  \
         "   " __stringify(instr) "  %3, %3, %4 // Toggle bit\n"             \
         "   strex  %0, %3, %2\n"                                            \
-        : "=&r" (res), "=&r" (oldbit), "+Qo" (*ptr), "=&r" (tmp)            \
+        : "=&r" (res), "=&r" (*oldbit), "+Qo" (*ptr), "=&r" (tmp)           \
         : "r" (mask), "r" (bit));                                           \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
                                                                             \
     smp_mb();                                                               \
                                                                             \
-    return oldbit & 1;                                                      \
+    *oldbit &= 1;                                                           \
+                                                                            \
+    return !res;                                                            \
+}                                                                           \
+                                                                            \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    int oldbit;                                                             \
+                                                                            \
+    if ( !int_##name(nr, p, &oldbit, false, 0) )                            \
+        ASSERT_UNREACHABLE();                                               \
+                                                                            \
+    return oldbit;                                                          \
 }                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p,                               \
+                    int *oldbit, unsigned int max_try)                      \
+{                                                                           \
+    return int_##name(nr, p, oldbit, true, max_try);                        \
+}
 
 bitop(change_bit, eor)
 bitop(clear_bit, bic)
diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
index b1c681c642..78bf4ed8c5 100644
--- a/xen/arch/arm/arm64/lib/bitops.c
+++ b/xen/arch/arm/arm64/lib/bitops.c
@@ -29,7 +29,8 @@
  */
 
 #define bitop(name, instr)                                                  \
-void name(int nr, volatile void *p)                                         \
+static always_inline bool int_##name(int nr, volatile void *p, bool timeout,\
+                                     unsigned int max_try)                  \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
@@ -43,17 +44,33 @@ void name(int nr, volatile void *p)                                         \
         "   stxr    %w0, %w2, %1\n"                                         \
         : "=&r" (res), "+Q" (*ptr), "=&r" (tmp)                             \
         : "r" (mask));                                                      \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
+                                                                            \
+    return !res;                                                            \
 }                                                                           \
+                                                                            \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    if ( !int_##name(nr, p, false, 0) )                                     \
+        ASSERT_UNREACHABLE();                                               \
+}                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p, unsigned int max_try)         \
+{                                                                           \
+    return int_##name(nr, p, true, max_try);                                \
+}
 
 #define testop(name, instr)                                                 \
-int name(int nr, volatile void *p)                                          \
+static always_inline bool int_##name(int nr, volatile void *p, int *oldbit, \
+                                     bool timeout, unsigned int max_try)    \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
     const uint32_t mask = BIT_MASK(bit);                                    \
     unsigned long res, tmp;                                                 \
-    unsigned long oldbit;                                                   \
                                                                             \
     do                                                                      \
     {                                                                       \
@@ -62,14 +79,35 @@ int name(int nr, volatile void *p)                                          \
         "   lsr     %w1, %w3, %w5 // Save old value of bit\n"               \
         "   " __stringify(instr) "  %w3, %w3, %w4 // Toggle bit\n"          \
         "   stlxr   %w0, %w3, %2\n"                                         \
-        : "=&r" (res), "=&r" (oldbit), "+Q" (*ptr), "=&r" (tmp)             \
+        : "=&r" (res), "=&r" (*oldbit), "+Q" (*ptr), "=&r" (tmp)            \
         : "r" (mask), "r" (bit)                                             \
         : "memory");                                                        \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
                                                                             \
     dmb(ish);                                                               \
                                                                             \
-    return oldbit & 1;                                                      \
+    *oldbit &= 1;                                                           \
+                                                                            \
+    return !res;                                                            \
+}                                                                           \
+                                                                            \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    int oldbit;                                                             \
+                                                                            \
+    if ( !int_##name(nr, p, &oldbit, false, 0) )                            \
+        ASSERT_UNREACHABLE();                                               \
+                                                                            \
+    return oldbit;                                                          \
+}                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p,                               \
+                    int *oldbit, unsigned int max_try)                      \
+{                                                                           \
+    return int_##name(nr, p, oldbit, true, max_try);                        \
 }
 
 bitop(change_bit, eor)
diff --git a/xen/include/asm-arm/bitops.h b/xen/include/asm-arm/bitops.h
index 8e864b4456..172bbaee7e 100644
--- a/xen/include/asm-arm/bitops.h
+++ b/xen/include/asm-arm/bitops.h
@@ -37,7 +37,14 @@
 # error "unknown ARM variant"
 #endif
 
-/* Atomics bitops */
+/*
+ * Atomic bitops
+ *
+ * The helpers below *should* only be used on memory shared between
+ * trusted threads or we know the memory cannot be accessed by another
+ * thread.
+ */
+
 void set_bit(int nr, volatile void *p);
 void clear_bit(int nr, volatile void *p);
 void change_bit(int nr, volatile void *p);
@@ -45,6 +52,25 @@ int test_and_set_bit(int nr, volatile void *p);
 int test_and_clear_bit(int nr, volatile void *p);
 int test_and_change_bit(int nr, volatile void *p);
 
+/*
+ * The helpers below may fail to update the memory if the action takes
+ * too long.
+ *
+ * @max_try: Maximum number of iterations
+ *
+ * The helpers will return true when the update has succeeded (i.e no
+ * timeout) and false if the update has failed.
+ */
+bool set_bit_timeout(int nr, volatile void *p, unsigned int max_try);
+bool clear_bit_timeout(int nr, volatile void *p, unsigned int max_try);
+bool change_bit_timeout(int nr, volatile void *p, unsigned int max_try);
+bool test_and_set_bit_timeout(int nr, volatile void *p,
+                              int *oldbit, unsigned int max_try);
+bool test_and_clear_bit_timeout(int nr, volatile void *p,
+                                int *oldbit, unsigned int max_try);
+bool test_and_change_bit_timeout(int nr, volatile void *p,
+                                 int *oldbit, unsigned int max_try);
+
 /**
  * __test_and_set_bit - Set a bit and return its old value
  * @nr: Bit to set
-- 
2.17.1
xsa295/4.8-12.patch (application/octet-stream, 8.3 KB)
From 13f426b833053bb33e9e3ec708a1349ed6a10d55 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Wed, 22 May 2019 13:39:17 -0700
Subject: [PATCH v2 4.8 12/21] xen/arm: cmpxchg: Provide a new helper that can
 timeout

Exclusive load-store atomics should only be used between trusted
threads. As not all the guests are trusted, it may be possible to DoS
Xen when updating shared memory with guest atomically.

To prevent the infinite loop, we introduce a new helper that can timeout.
The timeout is based on the maximum number of iterations.

It will be used in follow-up patch to make atomic operations on shared
memory safe.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm32/cmpxchg.h | 63 +++++++++++++++++++++-----
 xen/include/asm-arm/arm64/cmpxchg.h | 70 ++++++++++++++++++++++-------
 2 files changed, 106 insertions(+), 27 deletions(-)

diff --git a/xen/include/asm-arm/arm32/cmpxchg.h b/xen/include/asm-arm/arm32/cmpxchg.h
index 471a9e3a3f..49ca2a0d7a 100644
--- a/xen/include/asm-arm/arm32/cmpxchg.h
+++ b/xen/include/asm-arm/arm32/cmpxchg.h
@@ -55,11 +55,14 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
 extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
 
 #define __CMPXCHG_CASE(sz, name)					\
-static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
-						  unsigned long old,	\
-						  unsigned long new)	\
+static inline bool __cmpxchg_case_##name(volatile void *ptr,		\
+					 unsigned long *old,		\
+					 unsigned long new,		\
+					 bool timeout,			\
+					 unsigned int max_try)		\
 {									\
-	unsigned long oldval, res;					\
+	unsigned long oldval;						\
+	unsigned long res;						\
 									\
 	do {								\
 		asm volatile("@ __cmpxchg_case_" #name "\n"		\
@@ -68,29 +71,35 @@ static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
 		"	teq	%1, %3\n"				\
 		"	strex" #sz "eq %0, %4, [%2]\n"			\
 		: "=&r" (res), "=&r" (oldval)				\
-		: "r" (ptr), "Ir" (old), "r" (new)			\
+		: "r" (ptr), "Ir" (*old), "r" (new)			\
 		: "memory", "cc");					\
-	} while (res);							\
 									\
-	return oldval;							\
+		if (!res)						\
+			break;						\
+	} while (!timeout || ((--max_try) > 0));			\
+									\
+	*old = oldval;							\
+									\
+	return !res;							\
 }
 
 __CMPXCHG_CASE(b, 1)
 __CMPXCHG_CASE(h, 2)
 __CMPXCHG_CASE( , 4)
 
-static always_inline unsigned long __cmpxchg(
-    volatile void *ptr, unsigned long old, unsigned long new, int size)
+static always_inline bool __int_cmpxchg(volatile void *ptr, unsigned long *old,
+					unsigned long new, int size,
+					bool timeout, unsigned int max_try)
 {
 	prefetchw((const void *)ptr);
 
 	switch (size) {
 	case 1:
-		return __cmpxchg_case_1(ptr, old, new);
+		return __cmpxchg_case_1(ptr, old, new, timeout, max_try);
 	case 2:
-		return __cmpxchg_case_2(ptr, old, new);
+		return __cmpxchg_case_2(ptr, old, new, timeout, max_try);
 	case 4:
-		return __cmpxchg_case_4(ptr, old, new);
+		return __cmpxchg_case_4(ptr, old, new, timeout, max_try);
 	default:
 		return __bad_cmpxchg(ptr, size);
 	}
@@ -98,6 +107,17 @@ static always_inline unsigned long __cmpxchg(
 	ASSERT_UNREACHABLE();
 }
 
+static always_inline unsigned long __cmpxchg(volatile void *ptr,
+					     unsigned long old,
+					     unsigned long new,
+					     int size)
+{
+	if (!__int_cmpxchg(ptr, &old, new, size, false, 0))
+		ASSERT_UNREACHABLE();
+
+	return old;
+}
+
 static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
                                                 unsigned long old,
                                                 unsigned long new, int size)
@@ -111,6 +131,25 @@ static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
 	return ret;
 }
 
+/*
+ * The helper may fail to update the memory if the action takes too long.
+ *
+ * @old: On call the value pointed contains the expected old value. It will be
+ * updated to the actual old value.
+ * @max_try: Maximum number of iterations
+ *
+ * The helper will return true when the update has succeeded (i.e no
+ * timeout) and false if the update has failed.
+ */
+static always_inline bool __cmpxchg_mb_timeout(volatile void *ptr,
+					       unsigned long *old,
+					       unsigned long new,
+					       int size,
+					       unsigned int max_try)
+{
+	return __int_cmpxchg(ptr, old, new, size, true, max_try);
+}
+
 #define cmpxchg(ptr,o,n)						\
 	((__typeof__(*(ptr)))__cmpxchg_mb((ptr),			\
 					  (unsigned long)(o),		\
diff --git a/xen/include/asm-arm/arm64/cmpxchg.h b/xen/include/asm-arm/arm64/cmpxchg.h
index 393fbca6a5..5bc2e1f786 100644
--- a/xen/include/asm-arm/arm64/cmpxchg.h
+++ b/xen/include/asm-arm/arm64/cmpxchg.h
@@ -64,11 +64,14 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
 extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
 
 #define __CMPXCHG_CASE(w, sz, name)					\
-static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
-						  unsigned long old,	\
-						  unsigned long new)	\
+static inline bool __cmpxchg_case_##name(volatile void *ptr,		\
+					 unsigned long *old,		\
+					 unsigned long new,		\
+					 bool timeout,			\
+					 unsigned int max_try)		\
 {									\
-	unsigned long res, oldval;					\
+	unsigned long oldval;						\
+	unsigned long res;						\
 									\
 	do {								\
 		asm volatile("// __cmpxchg_case_" #name "\n"		\
@@ -80,11 +83,16 @@ static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
 		"1:\n"							\
 		: "=&r" (res), "=&r" (oldval),				\
 		  "+Q" (*(unsigned long *)ptr)				\
-		: "Ir" (old), "r" (new)					\
+		: "Ir" (*old), "r" (new)				\
 		: "cc");						\
-	} while (res);							\
 									\
-	return oldval;							\
+		if (!res)						\
+			break;						\
+	} while (!timeout || ((--max_try) > 0));			\
+									\
+	*old = oldval;							\
+									\
+	return !res;							\
 }
 
 __CMPXCHG_CASE(w, b, 1)
@@ -92,18 +100,19 @@ __CMPXCHG_CASE(w, h, 2)
 __CMPXCHG_CASE(w,  , 4)
 __CMPXCHG_CASE( ,  , 8)
 
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
-				      unsigned long new, int size)
+static always_inline bool __int_cmpxchg(volatile void *ptr, unsigned long *old,
+					unsigned long new, int size,
+					bool timeout, unsigned int max_try)
 {
 	switch (size) {
 	case 1:
-		return __cmpxchg_case_1(ptr, old, new);
+		return __cmpxchg_case_1(ptr, old, new, timeout, max_try);
 	case 2:
-		return __cmpxchg_case_2(ptr, old, new);
+		return __cmpxchg_case_2(ptr, old, new, timeout, max_try);
 	case 4:
-		return __cmpxchg_case_4(ptr, old, new);
+		return __cmpxchg_case_4(ptr, old, new, timeout, max_try);
 	case 8:
-		return __cmpxchg_case_8(ptr, old, new);
+		return __cmpxchg_case_8(ptr, old, new, timeout, max_try);
 	default:
 		return __bad_cmpxchg(ptr, size);
 	}
@@ -111,8 +120,20 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 	ASSERT_UNREACHABLE();
 }
 
-static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
-					 unsigned long new, int size)
+static always_inline unsigned long __cmpxchg(volatile void *ptr,
+					     unsigned long old,
+					     unsigned long new,
+					     int size)
+{
+	if (!__int_cmpxchg(ptr, &old, new, size, false, 0))
+		ASSERT_UNREACHABLE();
+
+	return old;
+}
+
+static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
+						unsigned long old,
+						unsigned long new, int size)
 {
 	unsigned long ret;
 
@@ -123,6 +144,25 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
 	return ret;
 }
 
+/*
+ * The helper may fail to update the memory if the action takes too long.
+ *
+ * @old: On call the value pointed contains the expected old value. It will be
+ * updated to the actual old value.
+ * @max_try: Maximum number of iterations
+ *
+ * The helper will return true when the update has succeeded (i.e no
+ * timeout) and false if the update has failed.
+ */
+static always_inline bool __cmpxchg_mb_timeout(volatile void *ptr,
+					       unsigned long *old,
+					       unsigned long new,
+					       int size,
+					       unsigned int max_try)
+{
+	return __int_cmpxchg(ptr, old, new, size, true, max_try);
+}
+
 #define cmpxchg(ptr, o, n) \
 ({ \
 	__typeof__(*(ptr)) __ret; \
-- 
2.17.1
xsa295/4.8-13.patch (application/octet-stream, 806 B)
From 9c90993cce85ac8def1fd2c217cf9648fe5dd672 Mon Sep 17 00:00:00 2001
From: Xin Li <[email protected]>
Date: Tue, 9 Oct 2018 17:33:18 +0800
Subject: [PATCH v2 4.8 13/21] xen/xsm: remove unnecessary #define

this #define is unnecessary since XSM_INLINE is redefined in
xsm/dummy.h, it's a risk of build breakage, so remove it.

Signed-off-by: Xin Li <[email protected]>
Reviewed-by: Jan Beulich <[email protected]>
Acked-by: Daniel De Graaf <[email protected]>
---
 xen/xsm/dummy.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c
index a082b28171..87fdb2b825 100644
--- a/xen/xsm/dummy.c
+++ b/xen/xsm/dummy.c
@@ -11,7 +11,6 @@
  */
 
 #define XSM_NO_WRAPPERS
-#define XSM_INLINE /* */
 #include <xsm/dummy.h>
 
 struct xsm_operations dummy_xsm_ops;
-- 
2.17.1
xsa295/4.8-14.patch (application/octet-stream, 3.8 KB)
From 52a7d20cc1881a5ddc7427139c9b22aecd486319 Mon Sep 17 00:00:00 2001
From: Xin Li <[email protected]>
Date: Tue, 9 Oct 2018 17:33:19 +0800
Subject: [PATCH v2 4.8 14/21] xen/xsm: Introduce new boot parameter xsm

Introduce new boot parameter xsm to choose which xsm module is enabled,
and set default to dummy. And add new option in Kconfig to choose the
default XSM implementation.

Signed-off-by: Xin Li <[email protected]>
Acked-by: Daniel De Graaf <[email protected]>
Acked-by: Andrew Cooper <[email protected]>
---
 docs/misc/xen-command-line.markdown | 13 +++++++++
 xen/common/Kconfig                  | 13 ++++++++-
 xen/xsm/xsm_core.c                  | 44 ++++++++++++++++++++++++++++-
 3 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/docs/misc/xen-command-line.markdown b/docs/misc/xen-command-line.markdown
index 87ca056726..4396aa2c44 100644
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -776,6 +776,19 @@ hardware domain is architecture dependent.
 Note that specifying zero as domU value means zero, while for dom0 it means
 to use the default.
 
+### xsm
+> `= dummy | flask`
+
+> Default: `dummy`
+
+Specify which XSM module should be enabled.  This option is only available if
+the hypervisor was compiled with XSM support.
+
+* `dummy`: this is the default choice.  Basic restriction for common deployment
+  (the dummy module) will be applied.  It's also used when XSM is compiled out.
+* `flask`: this is the policy based access control.  To choose this, the
+  separated option in kconfig must also be enabled.
+
 ### flask
 > `= permissive | enforcing | late | disabled`
 
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index f2ecbc43d6..de6308a487 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -99,7 +99,7 @@ config XSM
 
 config FLASK
 	def_bool y
-	prompt "FLux Advanced Security Kernel support" if EXPERT = "y"
+	prompt "FLux Advanced Security Kernel support"
 	depends on XSM
 	---help---
 	  Enables FLASK (FLux Advanced Security Kernel) as the access control
@@ -137,6 +137,17 @@ config XSM_POLICY
 
 	  If unsure, say Y.
 
+choice
+	prompt "Default XSM implementation"
+	depends on XSM
+	default XSM_FLASK_DEFAULT if XSM_FLASK
+	default XSM_DUMMY_DEFAULT
+	config XSM_DUMMY_DEFAULT
+		bool "Match non-XSM behavior"
+	config XSM_FLASK_DEFAULT
+		bool "FLux Advanced Security Kernel" if XSM_FLASK
+endchoice
+
 config LATE_HWDOM
 	bool "Dedicated hardware domain"
 	default n
diff --git a/xen/xsm/xsm_core.c b/xen/xsm/xsm_core.c
index 08994ee7a1..e78f7d8ca2 100644
--- a/xen/xsm/xsm_core.c
+++ b/xen/xsm/xsm_core.c
@@ -27,6 +27,35 @@
 
 struct xsm_operations *xsm_ops;
 
+enum xsm_bootparam {
+    XSM_BOOTPARAM_DUMMY,
+    XSM_BOOTPARAM_FLASK,
+};
+
+static enum xsm_bootparam __initdata xsm_bootparam =
+#ifdef CONFIG_XSM_FLASK_DEFAULT
+    XSM_BOOTPARAM_FLASK;
+#else
+    XSM_BOOTPARAM_DUMMY;
+#endif
+
+static int __init parse_xsm_param(const char *s)
+{
+    int rc = 0;
+
+    if ( !strcmp(s, "dummy") )
+        xsm_bootparam = XSM_BOOTPARAM_DUMMY;
+#ifdef CONFIG_XSM_FLASK
+    else if ( !strcmp(s, "flask") )
+        xsm_bootparam = XSM_BOOTPARAM_FLASK;
+#endif
+    else
+        rc = -EINVAL;
+
+    return rc;
+}
+custom_param("xsm", parse_xsm_param);
+
 static inline int verify(struct xsm_operations *ops)
 {
     /* verify the security_operations structure exists */
@@ -53,7 +82,20 @@ static int __init xsm_core_init(const void *policy_buffer, size_t policy_size)
     }
 
     xsm_ops = &dummy_xsm_ops;
-    flask_init(policy_buffer, policy_size);
+
+    switch ( xsm_bootparam )
+    {
+    case XSM_BOOTPARAM_DUMMY:
+        break;
+
+    case XSM_BOOTPARAM_FLASK:
+        flask_init(policy_buffer, policy_size);
+        break;
+
+    default:
+        ASSERT_UNREACHABLE();
+        break;
+    }
 
     return 0;
 }
-- 
2.17.1
xsa295/4.8-15.patch (application/octet-stream, 8.3 KB)
From 637098cc91ceb2f914c356cbd103c1e5513e7645 Mon Sep 17 00:00:00 2001
From: Xin Li <[email protected]>
Date: Tue, 9 Oct 2018 17:33:20 +0800
Subject: [PATCH v2 4.8 15/21] xen/xsm: Add new SILO mode for XSM

When SILO is enabled, there would be no page-sharing or event notifications
between unprivileged VMs (no grant tables or event channels).

Signed-off-by: Xin Li <[email protected]>
Acked-by: Daniel De Graaf <[email protected]>
Acked-by: Andrew Cooper <[email protected]>
---
 docs/misc/xen-command-line.markdown |   5 +-
 xen/common/Kconfig                  |  15 ++++
 xen/include/xsm/dummy.h             |   3 +-
 xen/include/xsm/xsm.h               |   6 ++
 xen/xsm/Makefile                    |   1 +
 xen/xsm/silo.c                      | 108 ++++++++++++++++++++++++++++
 xen/xsm/xsm_core.c                  |  11 +++
 7 files changed, 147 insertions(+), 2 deletions(-)
 create mode 100644 xen/xsm/silo.c

diff --git a/docs/misc/xen-command-line.markdown b/docs/misc/xen-command-line.markdown
index 4396aa2c44..7f60ddbbc6 100644
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -777,7 +777,7 @@ Note that specifying zero as domU value means zero, while for dom0 it means
 to use the default.
 
 ### xsm
-> `= dummy | flask`
+> `= dummy | flask | silo`
 
 > Default: `dummy`
 
@@ -788,6 +788,9 @@ the hypervisor was compiled with XSM support.
   (the dummy module) will be applied.  It's also used when XSM is compiled out.
 * `flask`: this is the policy based access control.  To choose this, the
   separated option in kconfig must also be enabled.
+* `silo`: this will deny any unmediated communication channels between
+  unprivileged VMs.  To choose this, the separated option in kconfig must also
+  be enabled.
 
 ### flask
 > `= permissive | enforcing | late | disabled`
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index de6308a487..ac93928207 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -137,15 +137,30 @@ config XSM_POLICY
 
 	  If unsure, say Y.
 
+config XSM_SILO
+	def_bool y
+	prompt "SILO support"
+	depends on XSM
+	---help---
+	  Enables SILO as the access control mechanism used by the XSM framework.
+	  This is not the default module, add boot parameter xsm=silo to choose
+	  it. This will deny any unmediated communication channels (grant tables
+	  and event channels) between unprivileged VMs.
+
+	  If unsure, say Y.
+
 choice
 	prompt "Default XSM implementation"
 	depends on XSM
 	default XSM_FLASK_DEFAULT if XSM_FLASK
+	default XSM_SILO_DEFAULT if XSM_SILO
 	default XSM_DUMMY_DEFAULT
 	config XSM_DUMMY_DEFAULT
 		bool "Match non-XSM behavior"
 	config XSM_FLASK_DEFAULT
 		bool "FLux Advanced Security Kernel" if XSM_FLASK
+	config XSM_SILO_DEFAULT
+		bool "SILO" if XSM_SILO
 endchoice
 
 config LATE_HWDOM
diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h
index 6c80aad14c..7c887880aa 100644
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -34,7 +34,8 @@ void __xsm_action_mismatch_detected(void);
  * There is no xsm_default_t argument available, so the value from the assertion
  * is used to initialize the variable.
  */
-#define XSM_INLINE /* */
+#define XSM_INLINE __maybe_unused
+
 #define XSM_DEFAULT_ARG /* */
 #define XSM_DEFAULT_VOID void
 #define XSM_ASSERT_ACTION(def) xsm_default_t action = def; (void)action
diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h
index 5dc59ddfd6..900d7d5f6e 100644
--- a/xen/include/xsm/xsm.h
+++ b/xen/include/xsm/xsm.h
@@ -766,6 +766,12 @@ extern const unsigned char xsm_init_policy[];
 extern const unsigned int xsm_init_policy_size;
 #endif
 
+#ifdef CONFIG_XSM_SILO
+extern void silo_init(void);
+#else
+static inline void silo_init(void) {}
+#endif
+
 #else /* CONFIG_XSM */
 
 #include <xsm/dummy.h>
diff --git a/xen/xsm/Makefile b/xen/xsm/Makefile
index 3252c46e64..50e21303b3 100644
--- a/xen/xsm/Makefile
+++ b/xen/xsm/Makefile
@@ -1,5 +1,6 @@
 obj-y += xsm_core.o
 obj-$(CONFIG_XSM) += xsm_policy.o
 obj-$(CONFIG_XSM) += dummy.o
+obj-$(CONFIG_XSM_SILO) += silo.o
 
 subdir-$(CONFIG_FLASK) += flask
diff --git a/xen/xsm/silo.c b/xen/xsm/silo.c
new file mode 100644
index 0000000000..4850756a3d
--- /dev/null
+++ b/xen/xsm/silo.c
@@ -0,0 +1,108 @@
+/******************************************************************************
+ * xsm/silo.c
+ *
+ * SILO module for XSM (Xen Security Modules)
+ *
+ * Copyright (c) 2018 Citrix Systems Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+#define XSM_NO_WRAPPERS
+#include <xsm/dummy.h>
+
+/*
+ * Check if inter-domain communication is allowed.
+ * Return true when pass check.
+ */
+static bool silo_mode_dom_check(const struct domain *ldom,
+                                const struct domain *rdom)
+{
+    const struct domain *currd = current->domain;
+
+    return (is_control_domain(currd) || is_control_domain(ldom) ||
+            is_control_domain(rdom) || ldom == rdom);
+}
+
+static int silo_evtchn_unbound(struct domain *d1, struct evtchn *chn,
+                               domid_t id2)
+{
+    int rc = -EPERM;
+    struct domain *d2 = rcu_lock_domain_by_any_id(id2);
+
+    if ( d2 == NULL )
+        rc = -ESRCH;
+    else
+    {
+        if ( silo_mode_dom_check(d1, d2) )
+            rc = xsm_evtchn_unbound(d1, chn, id2);
+        rcu_unlock_domain(d2);
+    }
+
+    return rc;
+}
+
+static int silo_evtchn_interdomain(struct domain *d1, struct evtchn *chan1,
+                                   struct domain *d2, struct evtchn *chan2)
+{
+    if ( silo_mode_dom_check(d1, d2) )
+        return xsm_evtchn_interdomain(d1, chan1, d2, chan2);
+    return -EPERM;
+}
+
+static int silo_grant_mapref(struct domain *d1, struct domain *d2,
+                             uint32_t flags)
+{
+    if ( silo_mode_dom_check(d1, d2) )
+        return xsm_grant_mapref(d1, d2, flags);
+    return -EPERM;
+}
+
+static int silo_grant_transfer(struct domain *d1, struct domain *d2)
+{
+    if ( silo_mode_dom_check(d1, d2) )
+        return xsm_grant_transfer(d1, d2);
+    return -EPERM;
+}
+
+static int silo_grant_copy(struct domain *d1, struct domain *d2)
+{
+    if ( silo_mode_dom_check(d1, d2) )
+        return xsm_grant_copy(d1, d2);
+    return -EPERM;
+}
+
+static struct xsm_operations silo_xsm_ops = {
+    .evtchn_unbound = silo_evtchn_unbound,
+    .evtchn_interdomain = silo_evtchn_interdomain,
+    .grant_mapref = silo_grant_mapref,
+    .grant_transfer = silo_grant_transfer,
+    .grant_copy = silo_grant_copy,
+};
+
+void __init silo_init(void)
+{
+    printk("Initialising XSM SILO mode\n");
+
+    if ( register_xsm(&silo_xsm_ops) )
+        panic("SILO: Unable to register with XSM\n");
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/xsm/xsm_core.c b/xen/xsm/xsm_core.c
index e78f7d8ca2..91ef8a70b7 100644
--- a/xen/xsm/xsm_core.c
+++ b/xen/xsm/xsm_core.c
@@ -30,11 +30,14 @@ struct xsm_operations *xsm_ops;
 enum xsm_bootparam {
     XSM_BOOTPARAM_DUMMY,
     XSM_BOOTPARAM_FLASK,
+    XSM_BOOTPARAM_SILO,
 };
 
 static enum xsm_bootparam __initdata xsm_bootparam =
 #ifdef CONFIG_XSM_FLASK_DEFAULT
     XSM_BOOTPARAM_FLASK;
+#elif CONFIG_XSM_SILO_DEFAULT
+    XSM_BOOTPARAM_SILO;
 #else
     XSM_BOOTPARAM_DUMMY;
 #endif
@@ -48,6 +51,10 @@ static int __init parse_xsm_param(const char *s)
 #ifdef CONFIG_XSM_FLASK
     else if ( !strcmp(s, "flask") )
         xsm_bootparam = XSM_BOOTPARAM_FLASK;
+#endif
+#ifdef CONFIG_XSM_SILO
+    else if ( !strcmp(s, "silo") )
+        xsm_bootparam = XSM_BOOTPARAM_SILO;
 #endif
     else
         rc = -EINVAL;
@@ -92,6 +99,10 @@ static int __init xsm_core_init(const void *policy_buffer, size_t policy_size)
         flask_init(policy_buffer, policy_size);
         break;
 
+    case XSM_BOOTPARAM_SILO:
+        silo_init();
+        break;
+
     default:
         ASSERT_UNREACHABLE();
         break;
-- 
2.17.1
xsa295/4.8-16.patch (application/octet-stream, 3.5 KB)
From 4b232aede0adf85da55b69f3189b37b3183c3695 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:25 +0100
Subject: [PATCH v2 4.8 16/21] xen/arm: Turn on SILO mode by default on Arm

On Arm, exclusive load-store atomics should only be used between trusted
thread. As not all the guests are trusted, it may be possible to DoS Xen
when updating shared memory with guest atomically.

Recent patches introduced new helpers to update shared memory with guest
atomically. Those helpers relies on a memory region to be be shared with
Xen and a single guest.

At the moment, nothing prevent a guest sharing a page with Xen and as
well with another guest (e.g via grant table).

For the scope of the XSA, the quickest way is to deny communications
between unprivileged guest. So this patch is enabling and using SILO
mode by default on Arm.

Users wanted finer graine policy could wrote their own Flask policy.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Acked-by: Jan Beulich <[email protected]>
---
 xen/arch/arm/setup.c  | 8 ++++++--
 xen/common/Kconfig    | 3 ++-
 xen/include/xsm/xsm.h | 5 +++++
 xen/xsm/xsm_core.c    | 2 +-
 4 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index 6116caa7ec..64143d34c5 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -38,6 +38,7 @@
 #include <xen/vmap.h>
 #include <xen/libfdt/libfdt.h>
 #include <xen/acpi.h>
+#include <xen/warning.h>
 #include <asm/alternative.h>
 #include <asm/page.h>
 #include <asm/current.h>
@@ -801,8 +802,11 @@ void __init start_xen(unsigned long boot_phys_offset,
 
     tasklet_subsys_init();
 
-
-    xsm_dt_init();
+    if ( xsm_dt_init() != 1 )
+        warning_add("WARNING: SILO mode is not enabled.\n"
+                    "It has implications on the security of the system,\n"
+                    "unless the communications have been forbidden between\n"
+                    "untrusted domains.\n");
 
     init_maintenance_interrupt();
     init_timer_interrupt();
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index ac93928207..618e252351 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -87,7 +87,7 @@ config XENOPROF
 
 config XSM
 	bool "Xen Security Modules support"
-	default n
+	default ARM
 	---help---
 	  Enables the security framework known as Xen Security Modules which
 	  allows administrators fine-grained control over a Xen domain and
@@ -152,6 +152,7 @@ config XSM_SILO
 choice
 	prompt "Default XSM implementation"
 	depends on XSM
+	default XSM_SILO_DEFAULT if XSM_SILO && ARM
 	default XSM_FLASK_DEFAULT if XSM_FLASK
 	default XSM_SILO_DEFAULT if XSM_SILO
 	default XSM_DUMMY_DEFAULT
diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h
index 900d7d5f6e..06e7c22632 100644
--- a/xen/include/xsm/xsm.h
+++ b/xen/include/xsm/xsm.h
@@ -743,6 +743,11 @@ extern int xsm_multiboot_policy_init(unsigned long *module_map,
 #endif
 
 #ifdef CONFIG_HAS_DEVICE_TREE
+/*
+ * Initialize XSM
+ *
+ * On success, return 1 if using SILO mode else 0.
+ */
 extern int xsm_dt_init(void);
 extern int xsm_dt_policy_init(void **policy_buffer, size_t *policy_size);
 extern bool has_xsm_magic(paddr_t);
diff --git a/xen/xsm/xsm_core.c b/xen/xsm/xsm_core.c
index 91ef8a70b7..2a2100929d 100644
--- a/xen/xsm/xsm_core.c
+++ b/xen/xsm/xsm_core.c
@@ -164,7 +164,7 @@ int __init xsm_dt_init(void)
 
     xfree(policy_buffer);
 
-    return ret;
+    return ret ?: (xsm_bootparam == XSM_BOOTPARAM_SILO);
 }
 
 /**
-- 
2.17.1
xsa295/4.8-17.patch (application/octet-stream, 9.7 KB)
From 88012e7e330c3fae8859e4c50e0f7884f738fa15 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:26 +0100
Subject: [PATCH v2 4.8 17/21] xen/bitops: Provide helpers to safely modify
 guest memory atomically

On Arm, exclusive load-store atomics should only be used between trusted
thread. As not all the guests are trusted, it may be possible to DoS Xen
when updating shared memory with guest atomically.

This patch adds a new set of helper that will update the guest memory
safely. For x86, it is already possible to use the current helpers
safely. So just wrap them.

For Arm, we will first attempt to update the guest memory with the loop
bounded by a maximum number of iterations. If it fails, we will pause the
domain and try again.

Note that this heuristics assumes that a page can only be shared between
Xen and one domain. Not Xen and multiple domain.

The maximum number of iterations is based on how many times a simple
load-store atomic operation can be executed in 1uS. The maximum value is
per-CPU to cater big.LITTLE and calculated when the CPU is booting. The
heuristic was randomly chosen and can be modified if impact too much
good-behaving guest.

Note, while test_bit does not requires to use atomic operation, a
wrapper for test_bit was added for completeness. In this case, the
domain stays constified to avoid major rework in the caller for the
time-being.

This is part of XSA-295.

Signed-of-by: Julien Grall <[email protected]>
Acked-by: Jan Beulich <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/Makefile               |  1 +
 xen/arch/arm/guest_atomics.c        | 91 +++++++++++++++++++++++++++++
 xen/include/asm-arm/guest_atomics.h | 76 ++++++++++++++++++++++++
 xen/include/asm-x86/guest_atomics.h | 30 ++++++++++
 4 files changed, 198 insertions(+)
 create mode 100644 xen/arch/arm/guest_atomics.c
 create mode 100644 xen/include/asm-arm/guest_atomics.h
 create mode 100644 xen/include/asm-x86/guest_atomics.h

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index da39d3919d..b7d3271099 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -19,6 +19,7 @@ obj-y += gic.o
 obj-y += gic-v2.o
 obj-$(CONFIG_HAS_GICV3) += gic-v3.o
 obj-y += guestcopy.o
+obj-y += guest_atomics.o
 obj-y += hvm.o
 obj-y += io.o
 obj-y += irq.o
diff --git a/xen/arch/arm/guest_atomics.c b/xen/arch/arm/guest_atomics.c
new file mode 100644
index 0000000000..1b78a062f0
--- /dev/null
+++ b/xen/arch/arm/guest_atomics.c
@@ -0,0 +1,91 @@
+/*
+ * arch/arm/guest_atomics.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <xen/cpu.h>
+
+#include <asm/guest_atomics.h>
+
+DEFINE_PER_CPU_READ_MOSTLY(unsigned int, guest_safe_atomic_max);
+
+/*
+ * Heuristic to find a safe upper-limit for load-store exclusive
+ * operations on memory shared with guest.
+ *
+ * At the moment, we calculate the number of iterations of a simple
+ * load-store atomic loop in 1uS.
+ */
+static void calibrate_safe_atomic(void)
+{
+    s_time_t deadline = NOW() + MICROSECS(1);
+    unsigned int counter = 0;
+    unsigned long mem = 0;
+
+    do
+    {
+        unsigned long res, tmp;
+
+#ifdef CONFIG_ARM_32
+        asm volatile (" ldrex   %2, %1\n"
+                      " add     %2, %2, #1\n"
+                      " strex   %0, %2, %1\n"
+                      : "=&r" (res), "+Q" (mem), "=&r" (tmp));
+#else
+        asm volatile (" ldxr    %w2, %1\n"
+                      " add     %w2, %w2, #1\n"
+                      " stxr    %w0, %w2, %1\n"
+                      : "=&r" (res), "+Q" (mem), "=&r" (tmp));
+#endif
+        counter++;
+    } while (NOW() < deadline);
+
+    this_cpu(guest_safe_atomic_max) = counter;
+
+    printk(XENLOG_DEBUG
+           "CPU%u: Guest atomics will try %u times before pausing the domain\n",
+           smp_processor_id(), counter);
+}
+
+static int cpu_guest_safe_atomic_callback(struct notifier_block *nfb,
+                                          unsigned long action,
+                                          void *hcpu)
+{
+    if ( action == CPU_STARTING )
+        calibrate_safe_atomic();
+
+    return NOTIFY_DONE;
+}
+
+static struct notifier_block cpu_guest_safe_atomic_nfb = {
+    .notifier_call = cpu_guest_safe_atomic_callback,
+};
+
+static int __init guest_safe_atomic_init(void)
+{
+    register_cpu_notifier(&cpu_guest_safe_atomic_nfb);
+
+    calibrate_safe_atomic();
+
+    return 0;
+}
+presmp_initcall(guest_safe_atomic_init);
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-arm/guest_atomics.h b/xen/include/asm-arm/guest_atomics.h
new file mode 100644
index 0000000000..4f127fda41
--- /dev/null
+++ b/xen/include/asm-arm/guest_atomics.h
@@ -0,0 +1,76 @@
+#ifndef _ARM_GUEST_ATOMICS_H
+#define _ARM_GUEST_ATOMICS_H
+
+#include <xen/bitops.h>
+#include <xen/sched.h>
+
+/*
+ * The guest atomics helpers shares the same logic. We first try to use
+ * the *_timeout version of the operation. If it didn't timeout, then we
+ * successfully updated the memory. Nothing else to do.
+ *
+ * If it did timeout, then it means we didn't manage to update the
+ * memory. This is possibly because the guest is misbehaving (i.e tight
+ * store loop) but can also happen for other reasons (i.e nested Xen).
+ * In that case pause the domain and retry the operation, this time
+ * without a timeout.
+ *
+ * Note, those helpers rely on other part of the code to prevent sharing
+ * a page between Xen and multiple domain.
+ */
+
+DECLARE_PER_CPU(unsigned int, guest_safe_atomic_max);
+
+#define guest_bitop(name)                                                   \
+static inline void guest_##name(struct domain *d, int nr, volatile void *p) \
+{                                                                           \
+    if ( name##_timeout(nr, p, this_cpu(guest_safe_atomic_max)) )           \
+        return;                                                             \
+                                                                            \
+    domain_pause_nosync(d);                                                 \
+    name(nr, p);                                                            \
+    domain_unpause(d);                                                      \
+}
+
+#define guest_testop(name)                                                  \
+static inline int guest_##name(struct domain *d, int nr, volatile void *p)  \
+{                                                                           \
+    bool succeed;                                                           \
+    int oldbit;                                                             \
+                                                                            \
+    succeed = name##_timeout(nr, p, &oldbit,                                \
+                             this_cpu(guest_safe_atomic_max));              \
+    if ( succeed )                                                          \
+        return oldbit;                                                      \
+                                                                            \
+    domain_pause_nosync(d);                                                 \
+    oldbit = name(nr, p);                                                   \
+    domain_unpause(d);                                                      \
+                                                                            \
+    return oldbit;                                                          \
+}
+
+guest_bitop(set_bit)
+guest_bitop(clear_bit)
+guest_bitop(change_bit)
+
+#undef guest_bitop
+
+/* test_bit does not use load-store atomic operations */
+#define guest_test_bit(d, nr, p) ((void)(d), test_bit(nr, p))
+
+guest_testop(test_and_set_bit)
+guest_testop(test_and_clear_bit)
+guest_testop(test_and_change_bit)
+
+#undef guest_testop
+
+#endif /* _ARM_GUEST_ATOMICS_H */
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-x86/guest_atomics.h b/xen/include/asm-x86/guest_atomics.h
new file mode 100644
index 0000000000..0c71d2d278
--- /dev/null
+++ b/xen/include/asm-x86/guest_atomics.h
@@ -0,0 +1,30 @@
+#ifndef _X86_GUEST_ATOMICS_H
+#define _X86_GUEST_ATOMICS_H
+
+#include <xen/bitops.h>
+
+/*
+ * It is safe to use the atomics helpers on x86 on memory shared with
+ * the guests.
+ */
+#define guest_set_bit(d, nr, p)     ((void)(d), set_bit(nr, p))
+#define guest_clear_bit(d, nr, p)   ((void)(d), clear_bit(nr, p))
+#define guest_change_bit(d, nr, p)  ((void)(d), change_bit(nr, p))
+#define guest_test_bit(d, nr, p)    ((void)(d), test_bit(nr, p))
+
+#define guest_test_and_set_bit(d, nr, p)    \
+    ((void)(d), test_and_set_bit(nr, p))
+#define guest_test_and_clear_bit(d, nr, p)  \
+    ((void)(d), test_and_clear_bit(nr, p))
+#define guest_test_and_change_bit(d, nr, p) \
+    ((void)(d), test_and_change_bit(nr, p))
+
+#endif /* _X86_GUEST_ATOMICS_H */
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.17.1
xsa295/4.8-18.patch (application/octet-stream, 3.4 KB)
From 22d39245c38e3a05ac7a0c684cdcab4d5cd3b33a Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:27 +0100
Subject: [PATCH v2 4.8 18/21] xen/cmpxchg: Provide helper to safely modify
 guest memory atomically

On Arm, exclusive load-store atomics should only be used between trusted
thread. As not all the guests are trusted, it may be possible to DoS Xen
when updating shared memory with guest atomically.

This patch adds a new helper that will update the guest memory safely.
For x86, it is already possible to use the current helper safely. So
just wrap it.

For Arm, we will first attempt to update the guest memory with the
loop bounded by a maximum number of iterations. If it fails, we will
pause the domain and try again.

Note that this heuristics assumes that a page can only
be shared between Xen and one domain. Not Xen and multiple domain.

The maximum number of iterations is based on how many times atomic_inc()
can be executed in 1uS. The maximum value is per-CPU to cater big.LITTLE
and calculated when the CPU is booting.

The maximum number of iterations is based on how many times a simple
load-store atomic operation can be executed in 1uS. The maximum
value is per-CPU to cater big.LITTLE and calculated when the CPU is
booting. The heuristic was randomly chosen and can be modified if
impact too much good-behaving guest.

This is part of XSA-295.

Signed-of-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Acked-by: Jan Beulich <[email protected]>
---
 xen/include/asm-arm/guest_atomics.h | 25 +++++++++++++++++++++++++
 xen/include/asm-x86/guest_atomics.h |  2 ++
 2 files changed, 27 insertions(+)

diff --git a/xen/include/asm-arm/guest_atomics.h b/xen/include/asm-arm/guest_atomics.h
index 4f127fda41..61925d313d 100644
--- a/xen/include/asm-arm/guest_atomics.h
+++ b/xen/include/asm-arm/guest_atomics.h
@@ -65,6 +65,31 @@ guest_testop(test_and_change_bit)
 
 #undef guest_testop
 
+static inline unsigned long __guest_cmpxchg(struct domain *d,
+                                            volatile void *ptr,
+                                            unsigned long old,
+                                            unsigned long new,
+                                            unsigned int size)
+{
+    unsigned long oldval = old;
+
+    if ( __cmpxchg_mb_timeout(ptr, &oldval, new, size,
+                              this_cpu(guest_safe_atomic_max)) )
+        return oldval;
+
+    domain_pause_nosync(d);
+    oldval = __cmpxchg_mb(ptr, old, new, size);
+    domain_unpause(d);
+
+    return oldval;
+}
+
+#define guest_cmpxchg(d, ptr, o, n)                         \
+    ((__typeof__(*(ptr)))__guest_cmpxchg(d, ptr,            \
+                                         (unsigned long)(o),\
+                                         (unsigned long)(n),\
+                                         sizeof (*(ptr))))
+
 #endif /* _ARM_GUEST_ATOMICS_H */
 /*
  * Local variables:
diff --git a/xen/include/asm-x86/guest_atomics.h b/xen/include/asm-x86/guest_atomics.h
index 0c71d2d278..029417c8ff 100644
--- a/xen/include/asm-x86/guest_atomics.h
+++ b/xen/include/asm-x86/guest_atomics.h
@@ -19,6 +19,8 @@
 #define guest_test_and_change_bit(d, nr, p) \
     ((void)(d), test_and_change_bit(nr, p))
 
+#define guest_cmpxchg(d, ptr, o, n) ((void)(d), cmpxchg(ptr, o, n))
+
 #endif /* _X86_GUEST_ATOMICS_H */
 /*
  * Local variables:
-- 
2.17.1
xsa295/4.8-19.patch (application/octet-stream, 22.5 KB)
From ce76ba49393ca5d2842405d044d6bf8c08ace357 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:28 +0100
Subject: [PATCH v2 4.8 19/21] xen: Use guest atomics helpers when modifying
 atomically guest memory

On Arm, exclusive load-store atomics should only be used between trusted
thread. As not all the guests are trusted, it may be possible to DoS Xen
when updating shared memory with guest atomically.

This patch replaces all the atomics operations on shared memory with
a guest by the new guest atomics helpers. The x86 code was not audited
to know where guest atomics helpers could be used. I will leave that
to the x86 folks.

Note that some rework was required in order to plumb use the new guest
atomics in event channel and grant-table.

Because guest_test_bit is ignoring the parameter "d" for now, it
means there a lot of places do not need to drop the const. We may want
to revisit this in the future if the parameter "d" becomes necessary.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/domain.c             |  3 +-
 xen/arch/arm/mm.c                 |  6 ++-
 xen/common/event_2l.c             | 26 +++++++------
 xen/common/event_fifo.c           | 44 +++++++++++-----------
 xen/common/grant_table.c          | 61 +++++++++++++++++--------------
 xen/include/asm-arm/grant_table.h |  2 +-
 xen/include/asm-x86/grant_table.h |  3 +-
 7 files changed, 80 insertions(+), 65 deletions(-)

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index c0a61da6f5..d9e796dcbe 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -24,6 +24,7 @@
 #include <asm/current.h>
 #include <asm/event.h>
 #include <asm/guest_access.h>
+#include <asm/guest_atomics.h>
 #include <asm/regs.h>
 #include <asm/p2m.h>
 #include <asm/irq.h>
@@ -935,7 +936,7 @@ void arch_dump_vcpu_info(struct vcpu *v)
 
 void vcpu_mark_events_pending(struct vcpu *v)
 {
-    int already_pending = test_and_set_bit(
+    bool already_pending = guest_test_and_set_bit(v->domain,
         0, (unsigned long *)&vcpu_info(v, evtchn_upcall_pending));
 
     if ( already_pending )
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 4c1a407c95..c991dbd178 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -41,6 +41,8 @@
 #include <xen/pfn.h>
 #include <xen/sizes.h>
 #include <xen/libfdt/libfdt.h>
+
+#include <asm/guest_atomics.h>
 #include <asm/setup.h>
 
 struct domain *dom_xen, *dom_io, *dom_cow;
@@ -1367,7 +1369,7 @@ void put_page_type(struct page_info *page)
     return;
 }
 
-void gnttab_clear_flag(unsigned long nr, uint16_t *addr)
+void gnttab_clear_flag(struct domain *d, unsigned long nr, uint16_t *addr)
 {
     /*
      * Note that this cannot be clear_bit(), as the access must be
@@ -1377,7 +1379,7 @@ void gnttab_clear_flag(unsigned long nr, uint16_t *addr)
 
     do {
         old = *addr;
-    } while (cmpxchg(addr, old, old & mask) != old);
+    } while (guest_cmpxchg(d, addr, old, old & mask) != old);
 }
 
 void gnttab_mark_dirty(struct domain *d, unsigned long l)
diff --git a/xen/common/event_2l.c b/xen/common/event_2l.c
index 42a5476498..6aabf0b9b0 100644
--- a/xen/common/event_2l.c
+++ b/xen/common/event_2l.c
@@ -14,6 +14,8 @@
 #include <xen/sched.h>
 #include <xen/event.h>
 
+#include <asm/guest_atomics.h>
+
 static void evtchn_2l_set_pending(struct vcpu *v, struct evtchn *evtchn)
 {
     struct domain *d = v->domain;
@@ -26,12 +28,12 @@ static void evtchn_2l_set_pending(struct vcpu *v, struct evtchn *evtchn)
      * others may require explicit memory barriers.
      */
 
-    if ( test_and_set_bit(port, &shared_info(d, evtchn_pending)) )
+    if ( guest_test_and_set_bit(d, port, &shared_info(d, evtchn_pending)) )
         return;
 
-    if ( !test_bit        (port, &shared_info(d, evtchn_mask)) &&
-         !test_and_set_bit(port / BITS_PER_EVTCHN_WORD(d),
-                           &vcpu_info(v, evtchn_pending_sel)) )
+    if ( !guest_test_bit(d, port, &shared_info(d, evtchn_mask)) &&
+         !guest_test_and_set_bit(d, port / BITS_PER_EVTCHN_WORD(d),
+                                 &vcpu_info(v, evtchn_pending_sel)) )
     {
         vcpu_mark_events_pending(v);
     }
@@ -41,7 +43,7 @@ static void evtchn_2l_set_pending(struct vcpu *v, struct evtchn *evtchn)
 
 static void evtchn_2l_clear_pending(struct domain *d, struct evtchn *evtchn)
 {
-    clear_bit(evtchn->port, &shared_info(d, evtchn_pending));
+    guest_clear_bit(d, evtchn->port, &shared_info(d, evtchn_pending));
 }
 
 static void evtchn_2l_unmask(struct domain *d, struct evtchn *evtchn)
@@ -53,10 +55,10 @@ static void evtchn_2l_unmask(struct domain *d, struct evtchn *evtchn)
      * These operations must happen in strict order. Based on
      * evtchn_2l_set_pending() above.
      */
-    if ( test_and_clear_bit(port, &shared_info(d, evtchn_mask)) &&
-         test_bit          (port, &shared_info(d, evtchn_pending)) &&
-         !test_and_set_bit (port / BITS_PER_EVTCHN_WORD(d),
-                            &vcpu_info(v, evtchn_pending_sel)) )
+    if ( guest_test_and_clear_bit(d, port, &shared_info(d, evtchn_mask)) &&
+         guest_test_bit(d, port, &shared_info(d, evtchn_pending)) &&
+         !guest_test_and_set_bit(d, port / BITS_PER_EVTCHN_WORD(d),
+                                 &vcpu_info(v, evtchn_pending_sel)) )
     {
         vcpu_mark_events_pending(v);
     }
@@ -67,7 +69,8 @@ static bool_t evtchn_2l_is_pending(struct domain *d, evtchn_port_t port)
     unsigned int max_ports = BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d);
 
     ASSERT(port < max_ports);
-    return port < max_ports && test_bit(port, &shared_info(d, evtchn_pending));
+    return (port < max_ports &&
+            guest_test_bit(d, port, &shared_info(d, evtchn_pending)));
 }
 
 static bool_t evtchn_2l_is_masked(struct domain *d, evtchn_port_t port)
@@ -75,7 +78,8 @@ static bool_t evtchn_2l_is_masked(struct domain *d, evtchn_port_t port)
     unsigned int max_ports = BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d);
 
     ASSERT(port < max_ports);
-    return port >= max_ports || test_bit(port, &shared_info(d, evtchn_mask));
+    return (port >= max_ports ||
+            guest_test_bit(d, port, &shared_info(d, evtchn_mask)));
 }
 
 static void evtchn_2l_print_state(struct domain *d,
diff --git a/xen/common/event_fifo.c b/xen/common/event_fifo.c
index fc58a4608a..08a8321f12 100644
--- a/xen/common/event_fifo.c
+++ b/xen/common/event_fifo.c
@@ -18,6 +18,8 @@
 #include <xen/mm.h>
 #include <xen/domain_page.h>
 
+#include <asm/guest_atomics.h>
+
 #include <public/event_channel.h>
 
 static inline event_word_t *evtchn_fifo_word_from_port(struct domain *d,
@@ -51,7 +53,7 @@ static void evtchn_fifo_init(struct domain *d, struct evtchn *evtchn)
      * on the wrong VCPU or with an unexpected priority.
      */
     word = evtchn_fifo_word_from_port(d, evtchn->port);
-    if ( word && test_bit(EVTCHN_FIFO_LINKED, word) )
+    if ( word && guest_test_bit(d, EVTCHN_FIFO_LINKED, word) )
         gdprintk(XENLOG_WARNING, "domain %d, port %d already on a queue\n",
                  d->domain_id, evtchn->port);
 }
@@ -116,7 +118,7 @@ static int try_set_link(event_word_t *word, event_word_t *w, uint32_t link)
  * We block unmasking by the guest by marking the tail word as BUSY,
  * therefore, the cmpxchg() may fail at most 4 times.
  */
-static bool_t evtchn_fifo_set_link(const struct domain *d, event_word_t *word,
+static bool_t evtchn_fifo_set_link(struct domain *d, event_word_t *word,
                                    uint32_t link)
 {
     event_word_t w;
@@ -130,7 +132,7 @@ static bool_t evtchn_fifo_set_link(const struct domain *d, event_word_t *word,
         return ret;
 
     /* Lock the word to prevent guest unmasking. */
-    set_bit(EVTCHN_FIFO_BUSY, word);
+    guest_set_bit(d, EVTCHN_FIFO_BUSY, word);
 
     w = read_atomic(word);
 
@@ -140,13 +142,13 @@ static bool_t evtchn_fifo_set_link(const struct domain *d, event_word_t *word,
         if ( ret >= 0 )
         {
             if ( ret == 0 )
-                clear_bit(EVTCHN_FIFO_BUSY, word);
+                guest_clear_bit(d, EVTCHN_FIFO_BUSY, word);
             return ret;
         }
     }
     gdprintk(XENLOG_WARNING, "domain %d, port %d not linked\n",
              d->domain_id, link);
-    clear_bit(EVTCHN_FIFO_BUSY, word);
+    guest_clear_bit(d, EVTCHN_FIFO_BUSY, word);
     return 1;
 }
 
@@ -171,13 +173,13 @@ static void evtchn_fifo_set_pending(struct vcpu *v, struct evtchn *evtchn)
         return;
     }
 
-    was_pending = test_and_set_bit(EVTCHN_FIFO_PENDING, word);
+    was_pending = guest_test_and_set_bit(d, EVTCHN_FIFO_PENDING, word);
 
     /*
      * Link the event if it unmasked and not already linked.
      */
-    if ( !test_bit(EVTCHN_FIFO_MASKED, word)
-         && !test_bit(EVTCHN_FIFO_LINKED, word) )
+    if ( !guest_test_bit(d, EVTCHN_FIFO_MASKED, word) &&
+         !guest_test_bit(d, EVTCHN_FIFO_LINKED, word) )
     {
         struct evtchn_fifo_queue *q, *old_q;
         event_word_t *tail_word;
@@ -206,7 +208,7 @@ static void evtchn_fifo_set_pending(struct vcpu *v, struct evtchn *evtchn)
         if ( !old_q )
             goto done;
 
-        if ( test_and_set_bit(EVTCHN_FIFO_LINKED, word) )
+        if ( guest_test_and_set_bit(d, EVTCHN_FIFO_LINKED, word) )
         {
             spin_unlock_irqrestore(&old_q->lock, flags);
             goto done;
@@ -252,8 +254,8 @@ static void evtchn_fifo_set_pending(struct vcpu *v, struct evtchn *evtchn)
         spin_unlock_irqrestore(&q->lock, flags);
 
         if ( !linked
-             && !test_and_set_bit(q->priority,
-                                  &v->evtchn_fifo->control_block->ready) )
+             && !guest_test_and_set_bit(d, q->priority,
+                                        &v->evtchn_fifo->control_block->ready) )
             vcpu_mark_events_pending(v);
     }
  done:
@@ -275,7 +277,7 @@ static void evtchn_fifo_clear_pending(struct domain *d, struct evtchn *evtchn)
      * No need to unlink as the guest will unlink and ignore
      * non-pending events.
      */
-    clear_bit(EVTCHN_FIFO_PENDING, word);
+    guest_clear_bit(d, EVTCHN_FIFO_PENDING, word);
 }
 
 static void evtchn_fifo_unmask(struct domain *d, struct evtchn *evtchn)
@@ -287,10 +289,10 @@ static void evtchn_fifo_unmask(struct domain *d, struct evtchn *evtchn)
     if ( unlikely(!word) )
         return;
 
-    clear_bit(EVTCHN_FIFO_MASKED, word);
+    guest_clear_bit(d, EVTCHN_FIFO_MASKED, word);
 
     /* Relink if pending. */
-    if ( test_bit(EVTCHN_FIFO_PENDING, word) )
+    if ( guest_test_bit(d, EVTCHN_FIFO_PENDING, word) )
         evtchn_fifo_set_pending(v, evtchn);
 }
 
@@ -302,7 +304,7 @@ static bool_t evtchn_fifo_is_pending(struct domain *d, evtchn_port_t port)
     if ( unlikely(!word) )
         return 0;
 
-    return test_bit(EVTCHN_FIFO_PENDING, word);
+    return word && guest_test_bit(d, EVTCHN_FIFO_PENDING, word);
 }
 
 static bool_t evtchn_fifo_is_masked(struct domain *d, evtchn_port_t port)
@@ -313,7 +315,7 @@ static bool_t evtchn_fifo_is_masked(struct domain *d, evtchn_port_t port)
     if ( unlikely(!word) )
         return 1;
 
-    return test_bit(EVTCHN_FIFO_MASKED, word);
+    return !word || guest_test_bit(d, EVTCHN_FIFO_MASKED, word);
 }
 
 static bool_t evtchn_fifo_is_busy(struct domain *d, evtchn_port_t port)
@@ -324,7 +326,7 @@ static bool_t evtchn_fifo_is_busy(struct domain *d, evtchn_port_t port)
     if ( unlikely(!word) )
         return 0;
 
-    return test_bit(EVTCHN_FIFO_LINKED, word);
+    return word && guest_test_bit(d, EVTCHN_FIFO_LINKED, word);
 }
 
 static int evtchn_fifo_set_priority(struct domain *d, struct evtchn *evtchn,
@@ -351,11 +353,11 @@ static void evtchn_fifo_print_state(struct domain *d,
     word = evtchn_fifo_word_from_port(d, evtchn->port);
     if ( !word )
         printk("?     ");
-    else if ( test_bit(EVTCHN_FIFO_LINKED, word) )
-        printk("%c %-4u", test_bit(EVTCHN_FIFO_BUSY, word) ? 'B' : ' ',
+    else if ( guest_test_bit(d, EVTCHN_FIFO_LINKED, word) )
+        printk("%c %-4u", guest_test_bit(d, EVTCHN_FIFO_BUSY, word) ? 'B' : ' ',
                *word & EVTCHN_FIFO_LINK_MASK);
     else
-        printk("%c -   ", test_bit(EVTCHN_FIFO_BUSY, word) ? 'B' : ' ');
+        printk("%c -   ", guest_test_bit(d, EVTCHN_FIFO_BUSY, word) ? 'B' : ' ');
 }
 
 static const struct evtchn_port_ops evtchn_port_ops_fifo =
@@ -507,7 +509,7 @@ static void setup_ports(struct domain *d)
 
         evtchn = evtchn_from_port(d, port);
 
-        if ( test_bit(port, &shared_info(d, evtchn_pending)) )
+        if ( guest_test_bit(d, port, &shared_info(d, evtchn_pending)) )
             evtchn->pending = 1;
 
         evtchn_fifo_set_priority(d, evtchn, EVTCHN_FIFO_PRIORITY_DEFAULT);
diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index a555dabbf7..c3c9e50d31 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -39,6 +39,7 @@
 #include <xen/vmap.h>
 #include <xsm/xsm.h>
 #include <asm/flushtlb.h>
+#include <asm/guest_atomics.h>
 
 /* 
  * This option is deprecated, use gnttab_max_frames and
@@ -546,6 +547,7 @@ static unsigned int nr_grant_entries(struct grant_table *gt)
 }
 
 static int _set_status_v1(const grant_entry_header_t *shah,
+                          struct domain *rd,
                           struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
@@ -601,8 +603,8 @@ static int _set_status_v1(const grant_entry_header_t *shah,
                          "Attempt to write-pin a r/o grant entry.\n");
         }
 
-        prev_scombo.word = cmpxchg((u32 *)shah,
-                                   scombo.word, new_scombo.word);
+        prev_scombo.word = guest_cmpxchg(rd, (u32 *)shah,
+                                         scombo.word, new_scombo.word);
         if ( likely(prev_scombo.word == scombo.word) )
             break;
 
@@ -619,6 +621,7 @@ done:
 
 static int _set_status_v2(const grant_entry_header_t *shah,
                           grant_status_t *status,
+                          struct domain *rd,
                           struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
@@ -681,8 +684,8 @@ static int _set_status_v2(const grant_entry_header_t *shah,
              (id != ldomid) ||
              (!readonly && (flags & GTF_readonly)) )
         {
-            gnttab_clear_flag(_GTF_writing, status);
-            gnttab_clear_flag(_GTF_reading, status);
+            gnttab_clear_flag(rd, _GTF_writing, status);
+            gnttab_clear_flag(rd, _GTF_reading, status);
             PIN_FAIL(done, GNTST_general_error,
                      "Unstable flags (%x) or dom (%d). (expected dom %d) "
                      "(r/w: %d)\n",
@@ -693,7 +696,7 @@ static int _set_status_v2(const grant_entry_header_t *shah,
     {
         if ( unlikely(flags & GTF_readonly) )
         {
-            gnttab_clear_flag(_GTF_writing, status);
+            gnttab_clear_flag(rd, _GTF_writing, status);
             PIN_FAIL(done, GNTST_general_error,
                      "Unstable grant readonly flag\n");
         }
@@ -706,6 +709,7 @@ done:
 
 static int _set_status(const grant_entry_header_t *shah,
                        grant_status_t *status,
+                       struct domain *rd,
                        unsigned rgt_version,
                        struct active_grant_entry *act,
                        int readonly,
@@ -714,9 +718,9 @@ static int _set_status(const grant_entry_header_t *shah,
 {
 
     if ( rgt_version == 1 )
-        return _set_status_v1(shah, act, readonly, mapflag, ldomid);
+        return _set_status_v1(shah, rd, act, readonly, mapflag, ldomid);
     else
-        return _set_status_v2(shah, status, act, readonly, mapflag, ldomid);
+        return _set_status_v2(shah, status, rd, act, readonly, mapflag, ldomid);
 }
 
 static struct active_grant_entry *grant_map_exists(const struct domain *ld,
@@ -884,7 +888,7 @@ __gnttab_map_grant_ref(
          (!(op->flags & GNTMAP_readonly) &&
           !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask))) )
     {
-        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+        if ( (rc = _set_status(shah, status, rd, rgt->gt_version, act,
                                op->flags & GNTMAP_readonly, 1,
                                ld->domain_id) != GNTST_okay) )
             goto act_release_out;
@@ -1097,10 +1101,10 @@ __gnttab_map_grant_ref(
  unlock_out_clear:
     if ( !(op->flags & GNTMAP_readonly) &&
          !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) )
-        gnttab_clear_flag(_GTF_writing, status);
+        gnttab_clear_flag(rd, _GTF_writing, status);
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 
  act_release_out:
     active_entry_release(act);
@@ -1382,10 +1386,10 @@ __gnttab_unmap_common_complete(struct gnttab_unmap_common *op)
 
     if ( ((act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0) &&
          !(op->done & GNTMAP_readonly) )
-        gnttab_clear_flag(_GTF_writing, status);
+        gnttab_clear_flag(rd, _GTF_writing, status);
 
     if ( act->pin == 0 )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 
     active_entry_release(act);
     grant_read_unlock(rgt);
@@ -1869,8 +1873,8 @@ gnttab_prepare_for_transfer(
         new_scombo = scombo;
         new_scombo.shorts.flags |= GTF_transfer_committed;
 
-        prev_scombo.word = cmpxchg((u32 *)&sha->flags,
-                                   scombo.word, new_scombo.word);
+        prev_scombo.word = guest_cmpxchg(rd, (u32 *)&sha->flags,
+                                         scombo.word, new_scombo.word);
         if ( likely(prev_scombo.word == scombo.word) )
             break;
 
@@ -2165,11 +2169,11 @@ __release_grant_for_copy(
 
         act->pin -= GNTPIN_hstw_inc;
         if ( !(act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) )
-            gnttab_clear_flag(_GTF_writing, status);
+            gnttab_clear_flag(rd, _GTF_writing, status);
     }
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 
     active_entry_release(act);
     grant_read_unlock(rgt);
@@ -2191,14 +2195,15 @@ __release_grant_for_copy(
    under the domain's grant table lock. */
 /* Only safe on transitive grants.  Even then, note that we don't
    attempt to drop any pin on the referent grant. */
-static void __fixup_status_for_copy_pin(const struct active_grant_entry *act,
-                                   uint16_t *status)
+static void __fixup_status_for_copy_pin(struct domain *rd,
+                                        const struct active_grant_entry *act,
+                                        uint16_t *status)
 {
     if ( !(act->pin & (GNTPIN_hstw_mask | GNTPIN_devw_mask)) )
-        gnttab_clear_flag(_GTF_writing, status);
+        gnttab_clear_flag(rd, _GTF_writing, status);
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 }
 
 /* Grab a frame number from a grant entry and update the flags and pin
@@ -2258,7 +2263,7 @@ __acquire_grant_for_copy(
     {
         if ( (!old_pin || (!readonly &&
                            !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)))) &&
-             (rc = _set_status_v2(shah, status, act, readonly, 0,
+             (rc = _set_status_v2(shah, status, rd, act, readonly, 0,
                                   ldom)) != GNTST_okay )
             goto unlock_out;
 
@@ -2306,7 +2311,7 @@ __acquire_grant_for_copy(
 
         if ( rc != GNTST_okay )
         {
-            __fixup_status_for_copy_pin(act, status);
+            __fixup_status_for_copy_pin(rd, act, status);
             rcu_unlock_domain(td);
             active_entry_release(act);
             grant_read_unlock(rgt);
@@ -2328,7 +2333,7 @@ __acquire_grant_for_copy(
                           !act->is_sub_page)) )
         {
             __release_grant_for_copy(td, trans_gref, readonly);
-            __fixup_status_for_copy_pin(act, status);
+            __fixup_status_for_copy_pin(rd, act, status);
             rcu_unlock_domain(td);
             active_entry_release(act);
             grant_read_unlock(rgt);
@@ -2357,7 +2362,7 @@ __acquire_grant_for_copy(
     else if ( !old_pin ||
               (!readonly && !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask))) )
     {
-        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+        if ( (rc = _set_status(shah, status, rd, rgt->gt_version, act,
                                readonly, 0, ldom)) != GNTST_okay )
              goto unlock_out;
 
@@ -2443,10 +2448,10 @@ __acquire_grant_for_copy(
  unlock_out_clear:
     if ( !(readonly) &&
          !(act->pin & (GNTPIN_hstw_mask | GNTPIN_devw_mask)) )
-        gnttab_clear_flag(_GTF_writing, status);
+        gnttab_clear_flag(rd, _GTF_writing, status);
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 
  unlock_out:
     active_entry_release(act);
@@ -3549,11 +3554,11 @@ gnttab_release_mappings(
             }
 
             if ( (act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0 )
-                gnttab_clear_flag(_GTF_writing, status);
+                gnttab_clear_flag(rd, _GTF_writing, status);
         }
 
         if ( act->pin == 0 )
-            gnttab_clear_flag(_GTF_reading, status);
+            gnttab_clear_flag(rd, _GTF_reading, status);
 
         active_entry_release(act);
         grant_read_unlock(rgt);
diff --git a/xen/include/asm-arm/grant_table.h b/xen/include/asm-arm/grant_table.h
index b47220c1c6..886f8398c3 100644
--- a/xen/include/asm-arm/grant_table.h
+++ b/xen/include/asm-arm/grant_table.h
@@ -6,7 +6,7 @@
 #define INITIAL_NR_GRANT_FRAMES 4
 #define GNTTAB_MAX_VERSION 1
 
-void gnttab_clear_flag(unsigned long nr, uint16_t *addr);
+void gnttab_clear_flag(struct domain *d, unsigned long nr, uint16_t *addr);
 int create_grant_host_mapping(unsigned long gpaddr,
         unsigned long mfn, unsigned int flags, unsigned int
         cache_flags);
diff --git a/xen/include/asm-x86/grant_table.h b/xen/include/asm-x86/grant_table.h
index 9c64361ee2..889b04cc88 100644
--- a/xen/include/asm-x86/grant_table.h
+++ b/xen/include/asm-x86/grant_table.h
@@ -56,7 +56,8 @@ int replace_grant_host_mapping(
 
 #define gnttab_mark_dirty(d, f) paging_mark_dirty((d), (f))
 
-static inline void gnttab_clear_flag(unsigned int nr, uint16_t *st)
+static inline void gnttab_clear_flag(struct domain *d, unsigned int nr,
+                                     uint16_t *st)
 {
     /*
      * Note that this cannot be clear_bit(), as the access must be
-- 
2.17.1
xsa295/4.8-20.patch (application/octet-stream, 4.1 KB)
From ecfbfbf547606e7ec595ecd0104b01a994ac37af Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:29 +0100
Subject: [PATCH v2 4.8 20/21] xen/arm: Add performance counters in guest
 atomic helpers

Add performance counters in guest atomic helpers to be able to detect
whether a guest is often paused during the operations.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Acked-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/guest_atomics.h | 12 ++++++++++++
 xen/include/asm-arm/perfc_defn.h    |  3 +++
 2 files changed, 15 insertions(+)

diff --git a/xen/include/asm-arm/guest_atomics.h b/xen/include/asm-arm/guest_atomics.h
index 61925d313d..698508bf87 100644
--- a/xen/include/asm-arm/guest_atomics.h
+++ b/xen/include/asm-arm/guest_atomics.h
@@ -24,9 +24,13 @@ DECLARE_PER_CPU(unsigned int, guest_safe_atomic_max);
 #define guest_bitop(name)                                                   \
 static inline void guest_##name(struct domain *d, int nr, volatile void *p) \
 {                                                                           \
+    perfc_incr(atomics_guest);                                              \
+                                                                            \
     if ( name##_timeout(nr, p, this_cpu(guest_safe_atomic_max)) )           \
         return;                                                             \
                                                                             \
+    perfc_incr(atomics_guest_paused);                                       \
+                                                                            \
     domain_pause_nosync(d);                                                 \
     name(nr, p);                                                            \
     domain_unpause(d);                                                      \
@@ -38,11 +42,15 @@ static inline int guest_##name(struct domain *d, int nr, volatile void *p)  \
     bool succeed;                                                           \
     int oldbit;                                                             \
                                                                             \
+    perfc_incr(atomics_guest);                                              \
+                                                                            \
     succeed = name##_timeout(nr, p, &oldbit,                                \
                              this_cpu(guest_safe_atomic_max));              \
     if ( succeed )                                                          \
         return oldbit;                                                      \
                                                                             \
+    perfc_incr(atomics_guest_paused);                                       \
+                                                                            \
     domain_pause_nosync(d);                                                 \
     oldbit = name(nr, p);                                                   \
     domain_unpause(d);                                                      \
@@ -73,10 +81,14 @@ static inline unsigned long __guest_cmpxchg(struct domain *d,
 {
     unsigned long oldval = old;
 
+    perfc_incr(atomics_guest);
+
     if ( __cmpxchg_mb_timeout(ptr, &oldval, new, size,
                               this_cpu(guest_safe_atomic_max)) )
         return oldval;
 
+    perfc_incr(atomics_guest_paused);
+
     domain_pause_nosync(d);
     oldval = __cmpxchg_mb(ptr, old, new, size);
     domain_unpause(d);
diff --git a/xen/include/asm-arm/perfc_defn.h b/xen/include/asm-arm/perfc_defn.h
index 69fabe7529..987fe7f86a 100644
--- a/xen/include/asm-arm/perfc_defn.h
+++ b/xen/include/asm-arm/perfc_defn.h
@@ -71,6 +71,9 @@ PERFCOUNTER(phys_timer_irqs,  "Physical timer interrupts")
 PERFCOUNTER(virt_timer_irqs,  "Virtual timer interrupts")
 PERFCOUNTER(maintenance_irqs, "Maintenance interrupts")
 
+PERFCOUNTER(atomics_guest,    "atomics: guest access")
+PERFCOUNTER(atomics_guest_paused,   "atomics: guest paused")
+
 /*#endif*/ /* __XEN_PERFC_DEFN_H__ */
 
 /*
-- 
2.17.1
xsa295/4.8-21.patch (application/octet-stream, 6.4 KB)
From 5a28a395d8f813d0dd17742345348481e4576b72 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:30 +0100
Subject: [PATCH v2 4.8 21/21] xen/arm: grant-table: Protect gnttab_clear_flag
 against guest misbehavior

The function gnttab_clear_flag is used to clear the access flags. On
Arm, it is implemented using a loop and guest_cmpxchg.

It is possible that guest_cmpxchg will always return a different value
than old. This can happen if the guest updated the memory before Xen has
time to do the exchange. Because of that, there are no way for to
promise the loop will end.

It is possible to make the current code safe by re-using the same
principle as applied on the guest atomic helper. However this patch
takes a different approach that should lead to more efficient code in
the default case.

A new helper is introduced to clear a set of bits on a 16-bits word.
This should avoid a an extra loop to check cmpxchg succeeded.

Note that a mask is used instead of a bit, so the helper can be re-used
later on for clearing multiple flags at the same time.

This is part of XSA-295.

Reported-by: Andrew Cooper <[email protected]>
Signed-off-by: Julien Grall <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/arm32/lib/bitops.c     | 35 +++++++++++++++++++++++++++++
 xen/arch/arm/arm64/lib/bitops.c     | 33 +++++++++++++++++++++++++++
 xen/arch/arm/mm.c                   | 10 +--------
 xen/include/asm-arm/bitops.h        |  4 ++++
 xen/include/asm-arm/guest_atomics.h | 13 +++++++++++
 5 files changed, 86 insertions(+), 9 deletions(-)

diff --git a/xen/arch/arm/arm32/lib/bitops.c b/xen/arch/arm/arm32/lib/bitops.c
index 08750314fc..3dca769bf0 100644
--- a/xen/arch/arm/arm32/lib/bitops.c
+++ b/xen/arch/arm/arm32/lib/bitops.c
@@ -126,6 +126,41 @@ testop(test_and_change_bit, eor)
 testop(test_and_clear_bit, bic)
 testop(test_and_set_bit, orr)
 
+static always_inline bool int_clear_mask16(uint16_t mask, volatile uint16_t *p,
+                                           bool timeout, unsigned int max_try)
+{
+    unsigned long res, tmp;
+
+    prefetchw((const uint16_t *)p);
+
+    do
+    {
+        asm volatile ("// int_clear_mask16\n"
+        "   ldrexh  %2, %1\n"
+        "   bic     %2, %2, %3\n"
+        "   strexh  %0, %2, %1\n"
+        : "=&r" (res), "+Qo" (*p), "=&r" (tmp)
+        : "r" (mask));
+
+        if ( !res )
+            break;
+    } while ( !timeout || ((--max_try) > 0) );
+
+    return !res;
+}
+
+void clear_mask16(uint16_t mask, volatile void *p)
+{
+    if ( !int_clear_mask16(mask, p, false, 0) )
+        ASSERT_UNREACHABLE();
+}
+
+bool clear_mask16_timeout(uint16_t mask, volatile void *p,
+                          unsigned int max_try)
+{
+    return int_clear_mask16(mask, p, true, max_try);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
index 78bf4ed8c5..27688e5418 100644
--- a/xen/arch/arm/arm64/lib/bitops.c
+++ b/xen/arch/arm/arm64/lib/bitops.c
@@ -118,6 +118,39 @@ testop(test_and_change_bit, eor)
 testop(test_and_clear_bit, bic)
 testop(test_and_set_bit, orr)
 
+static always_inline bool int_clear_mask16(uint16_t mask, volatile uint16_t *p,
+                                           bool timeout, unsigned int max_try)
+{
+    unsigned long res, tmp;
+
+    do
+    {
+        asm volatile ("//  int_clear_mask16\n"
+        "   ldxrh   %w2, %1\n"
+        "   bic     %w2, %w2, %w3\n"
+        "   stxrh   %w0, %w2, %1\n"
+        : "=&r" (res), "+Q" (*p), "=&r" (tmp)
+        : "r" (mask));
+
+        if ( !res )
+            break;
+    } while ( !timeout || ((--max_try) > 0) );
+
+    return !res;
+}
+
+void clear_mask16(uint16_t mask, volatile void *p)
+{
+    if ( !int_clear_mask16(mask, p, false, 0) )
+        ASSERT_UNREACHABLE();
+}
+
+bool clear_mask16_timeout(uint16_t mask, volatile void *p,
+                          unsigned int max_try)
+{
+    return int_clear_mask16(mask, p, true, max_try);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index c991dbd178..0f595bde8d 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -1371,15 +1371,7 @@ void put_page_type(struct page_info *page)
 
 void gnttab_clear_flag(struct domain *d, unsigned long nr, uint16_t *addr)
 {
-    /*
-     * Note that this cannot be clear_bit(), as the access must be
-     * confined to the specified 2 bytes.
-     */
-    uint16_t mask = ~(1 << nr), old;
-
-    do {
-        old = *addr;
-    } while (guest_cmpxchg(d, addr, old, old & mask) != old);
+    guest_clear_mask16(d, BIT(nr), addr);
 }
 
 void gnttab_mark_dirty(struct domain *d, unsigned long l)
diff --git a/xen/include/asm-arm/bitops.h b/xen/include/asm-arm/bitops.h
index 172bbaee7e..3b17db096f 100644
--- a/xen/include/asm-arm/bitops.h
+++ b/xen/include/asm-arm/bitops.h
@@ -52,6 +52,8 @@ int test_and_set_bit(int nr, volatile void *p);
 int test_and_clear_bit(int nr, volatile void *p);
 int test_and_change_bit(int nr, volatile void *p);
 
+void clear_mask16(uint16_t mask, volatile void *p);
+
 /*
  * The helpers below may fail to update the memory if the action takes
  * too long.
@@ -70,6 +72,8 @@ bool test_and_clear_bit_timeout(int nr, volatile void *p,
                                 int *oldbit, unsigned int max_try);
 bool test_and_change_bit_timeout(int nr, volatile void *p,
                                  int *oldbit, unsigned int max_try);
+bool clear_mask16_timeout(uint16_t mask, volatile void *p,
+                          unsigned int max_try);
 
 /**
  * __test_and_set_bit - Set a bit and return its old value
diff --git a/xen/include/asm-arm/guest_atomics.h b/xen/include/asm-arm/guest_atomics.h
index 698508bf87..af27cc627b 100644
--- a/xen/include/asm-arm/guest_atomics.h
+++ b/xen/include/asm-arm/guest_atomics.h
@@ -73,6 +73,19 @@ guest_testop(test_and_change_bit)
 
 #undef guest_testop
 
+static inline void guest_clear_mask16(struct domain *d, uint16_t mask,
+                                      volatile uint16_t *p)
+{
+    perfc_incr(atomics_guest);
+
+    if ( clear_mask16_timeout(mask, p, this_cpu(guest_safe_atomic_max)) )
+        return;
+
+    domain_pause_nosync(d);
+    clear_mask16(mask, p);
+    domain_unpause(d);
+}
+
 static inline unsigned long __guest_cmpxchg(struct domain *d,
                                             volatile void *ptr,
                                             unsigned long old,
-- 
2.17.1
xsa295/4.9-01.patch (application/octet-stream, 2.3 KB)
From 8252c8c877ebb1e4314e4ec01dddfe297907211b Mon Sep 17 00:00:00 2001
From: Jan Beulich <[email protected]>
Date: Thu, 23 May 2019 10:42:29 -0700
Subject: [PATCH v2 4.9 01/20] events: drop arch_evtchn_inject()

Have the only user call vcpu_mark_events_pending() instead, at the same
time arranging for correct ordering of the writes (evtchn_pending_sel
should be written before evtchn_upcall_pending).

Signed-off-by: Jan Beulich <[email protected]>
Reviewed-by: Andrew Cooper <[email protected]>
Reviewed-by: Julien Grall <[email protected]>
---
 xen/arch/arm/vgic.c     | 5 -----
 xen/common/domain.c     | 3 +--
 xen/include/xen/event.h | 3 ---
 3 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index cb4acb3f61..d9bacd07e7 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -530,11 +530,6 @@ void vgic_vcpu_inject_spi(struct domain *d, unsigned int virq)
     vgic_vcpu_inject_irq(v, virq);
 }
 
-void arch_evtchn_inject(struct vcpu *v)
-{
-    vgic_vcpu_inject_irq(v, v->domain->arch.evtchn_irq);
-}
-
 bool vgic_emulate(struct cpu_user_regs *regs, union hsr hsr)
 {
     struct vcpu *v = current;
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 7a944416ed..619bca8044 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -1203,10 +1203,9 @@ int map_vcpu_info(struct vcpu *v, unsigned long gfn, unsigned offset)
      * Mark everything as being pending just to make sure nothing gets
      * lost.  The domain will get a spurious event, but it can cope.
      */
-    vcpu_info(v, evtchn_upcall_pending) = 1;
     for ( i = 0; i < BITS_PER_EVTCHN_WORD(d); i++ )
         set_bit(i, &vcpu_info(v, evtchn_pending_sel));
-    arch_evtchn_inject(v);
+    vcpu_mark_events_pending(v);
 
     return 0;
 }
diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h
index 82caddbe76..945c2e7049 100644
--- a/xen/include/xen/event.h
+++ b/xen/include/xen/event.h
@@ -68,9 +68,6 @@ int guest_enabled_event(struct vcpu *v, uint32_t virq);
 /* Notify remote end of a Xen-attached event channel.*/
 void notify_via_xen_event_channel(struct domain *ld, int lport);
 
-/* Inject an event channel notification into the guest */
-void arch_evtchn_inject(struct vcpu *v);
-
 /*
  * Internal event channel object storage.
  *
-- 
2.17.1
xsa295/4.9-02.patch (application/octet-stream, 3.7 KB)
From f21a638a739d788723f609d7a4dc18a4afc17421 Mon Sep 17 00:00:00 2001
From: Jan Beulich <[email protected]>
Date: Tue, 12 Mar 2019 14:40:56 +0100
Subject: [PATCH v2 4.9 02/20] common: avoid atomic read-modify-write accesses
 in map_vcpu_info()

There's no need to set the evtchn_pending_sel bits one by one. Simply
write full words with all ones.

For Arm this requires extending write_atomic() to also handle 64-bit
values; for symmetry read_atomic() gets adjusted as well.

Signed-off-by: Jan Beulich <[email protected]>
Reviewed-by: Andrew Cooper <[email protected]>
Reviewed-by: Julien Grall <[email protected]>
---
 xen/common/domain.c          |  9 ++++++---
 xen/include/asm-arm/atomic.h | 15 +++++++++++++++
 2 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/xen/common/domain.c b/xen/common/domain.c
index 619bca8044..1bfec32e9c 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -1150,7 +1150,6 @@ int map_vcpu_info(struct vcpu *v, unsigned long gfn, unsigned offset)
     void *mapping;
     vcpu_info_t *new_info;
     struct page_info *page;
-    int i;
 
     if ( offset > (PAGE_SIZE - sizeof(vcpu_info_t)) )
         return -EINVAL;
@@ -1203,8 +1202,12 @@ int map_vcpu_info(struct vcpu *v, unsigned long gfn, unsigned offset)
      * Mark everything as being pending just to make sure nothing gets
      * lost.  The domain will get a spurious event, but it can cope.
      */
-    for ( i = 0; i < BITS_PER_EVTCHN_WORD(d); i++ )
-        set_bit(i, &vcpu_info(v, evtchn_pending_sel));
+#ifdef CONFIG_COMPAT
+    if ( !has_32bit_shinfo(d) )
+        write_atomic(&new_info->native.evtchn_pending_sel, ~0);
+    else
+#endif
+        write_atomic(&vcpu_info(v, evtchn_pending_sel), ~0);
     vcpu_mark_events_pending(v);
 
     return 0;
diff --git a/xen/include/asm-arm/atomic.h b/xen/include/asm-arm/atomic.h
index 50f2835e35..74c73e67c4 100644
--- a/xen/include/asm-arm/atomic.h
+++ b/xen/include/asm-arm/atomic.h
@@ -55,6 +55,19 @@ build_atomic_write(write_int_atomic, "",  WORD, int, "r")
 #if defined (CONFIG_ARM_64)
 build_atomic_read(read_u64_atomic, "", "", uint64_t, "=r")
 build_atomic_write(write_u64_atomic, "", "", uint64_t, "r")
+#elif defined (CONFIG_ARM_32)
+static inline uint64_t read_u64_atomic(const volatile uint64_t *addr)
+{
+    uint64_t val;
+
+    asm volatile ( "ldrd %0,%H0,%1" : "=r" (val) : "m" (*addr) );
+
+    return val;
+}
+static inline void write_u64_atomic(volatile uint64_t *addr, uint64_t val)
+{
+    asm volatile ( "strd %1,%H1,%0" : "=m" (*addr) : "r" (val) );
+}
 #endif
 
 build_add_sized(add_u8_sized, "b", BYTE, uint8_t, "ri")
@@ -69,6 +82,7 @@ void __bad_atomic_size(void);
     case 1: __x = (typeof(*p))read_u8_atomic((uint8_t *)p); break;      \
     case 2: __x = (typeof(*p))read_u16_atomic((uint16_t *)p); break;    \
     case 4: __x = (typeof(*p))read_u32_atomic((uint32_t *)p); break;    \
+    case 8: __x = (typeof(*p))read_u64_atomic((uint64_t *)p); break;    \
     default: __x = 0; __bad_atomic_size(); break;                       \
     }                                                                   \
     __x;                                                                \
@@ -80,6 +94,7 @@ void __bad_atomic_size(void);
     case 1: write_u8_atomic((uint8_t *)p, (uint8_t)__x); break;         \
     case 2: write_u16_atomic((uint16_t *)p, (uint16_t)__x); break;      \
     case 4: write_u32_atomic((uint32_t *)p, (uint32_t)__x); break;      \
+    case 8: write_u64_atomic((uint64_t *)p, (uint64_t)__x); break;      \
     default: __bad_atomic_size(); break;                                \
     }                                                                   \
     __x;                                                                \
-- 
2.17.1
xsa295/4.9-03.patch (application/octet-stream, 2.1 KB)
From bd39571d4bebc5b0ac69178e00da391935929114 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:16 +0100
Subject: [PATCH v2 4.9 03/20] xen/arm: Add an isb() before reading CNTPCT_EL0
 to prevent re-ordering

Per D8.2.1 in ARM DDI 0487C.a, "a read to CNTPCT_EL0 can occur
speculatively and out of order relative to other instructions executed
on the same PE."

Add an instruction barrier to get accurate number of cycles when
requested in get_cycles(). For the other users of CNPCT_EL0, replace by
a call to get_cycles().

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Acked-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/time.c        | 4 ++--
 xen/include/asm-arm/time.h | 5 ++++-
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/time.c b/xen/arch/arm/time.c
index 105c7410c7..825ef374e8 100644
--- a/xen/arch/arm/time.c
+++ b/xen/arch/arm/time.c
@@ -150,7 +150,7 @@ void __init preinit_xen_time(void)
     if ( res )
         panic("Timer: Cannot initialize platform timer");
 
-    boot_count = READ_SYSREG64(CNTPCT_EL0);
+    boot_count = get_cycles();
 }
 
 static void __init init_dt_xen_time(void)
@@ -191,7 +191,7 @@ int __init init_xen_time(void)
 /* Return number of nanoseconds since boot */
 s_time_t get_s_time(void)
 {
-    uint64_t ticks = READ_SYSREG64(CNTPCT_EL0) - boot_count;
+    uint64_t ticks = get_cycles() - boot_count;
     return ticks_to_ns(ticks);
 }
 
diff --git a/xen/include/asm-arm/time.h b/xen/include/asm-arm/time.h
index 5b9a31de91..ca30406669 100644
--- a/xen/include/asm-arm/time.h
+++ b/xen/include/asm-arm/time.h
@@ -1,6 +1,8 @@
 #ifndef __ARM_TIME_H__
 #define __ARM_TIME_H__
 
+#include <asm/system.h>
+
 #define DT_MATCH_TIMER                      \
     DT_MATCH_COMPATIBLE("arm,armv7-timer"), \
     DT_MATCH_COMPATIBLE("arm,armv8-timer")
@@ -9,7 +11,8 @@ typedef unsigned long cycles_t;
 
 static inline cycles_t get_cycles (void)
 {
-        return 0;
+        isb();
+        return READ_SYSREG64(CNTPCT_EL0);
 }
 
 /* List of timer's IRQ */
-- 
2.17.1
xsa295/4.9-04.patch (application/octet-stream, 6.7 KB)
From f88b188886d2948d1668450fae24169ca221a349 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:17 +0100
Subject: [PATCH v2 4.9 04/20] xen/grant_table: Rework the prototype of
 _set_status* for lisibility

It is not clear from the parameters name whether domid and gt_version
correspond to the local or remote domain. A follow-up patch will make
them more confusing.

So rename domid (resp. gt_version) to ldomid (resp. rgt_version). At
the same time re-order the parameters to hopefully make it more
readable.

This is part of XSA-295.

Suggested-by: Jan Beulich <[email protected]>
Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Jan Beulich <[email protected]>
Acked-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/common/grant_table.c | 57 ++++++++++++++++++++--------------------
 1 file changed, 28 insertions(+), 29 deletions(-)

diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index 5b338e95ff..670ae8e3aa 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -545,11 +545,11 @@ static unsigned int nr_grant_entries(struct grant_table *gt)
     return 0;
 }
 
-static int _set_status_v1(domid_t  domid,
+static int _set_status_v1(const grant_entry_header_t *shah,
+                          struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
-                          grant_entry_header_t *shah, 
-                          struct active_grant_entry *act)
+                          domid_t  ldomid)
 {
     int rc = GNTST_okay;
     union grant_combo scombo, prev_scombo, new_scombo;
@@ -584,11 +584,11 @@ static int _set_status_v1(domid_t  domid,
         if ( !act->pin &&
              (((scombo.shorts.flags & mask) !=
                GTF_permit_access) ||
-              (scombo.shorts.domid != domid)) )
+              (scombo.shorts.domid != ldomid)) )
             PIN_FAIL(done, GNTST_general_error,
                      "Bad flags (%x) or dom (%d). (expected dom %d)\n",
                      scombo.shorts.flags, scombo.shorts.domid,
-                     domid);
+                     ldomid);
 
         new_scombo = scombo;
         new_scombo.shorts.flags |= GTF_reading;
@@ -617,12 +617,12 @@ done:
     return rc;
 }
 
-static int _set_status_v2(domid_t  domid,
+static int _set_status_v2(const grant_entry_header_t *shah,
+                          grant_status_t *status,
+                          struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
-                          grant_entry_header_t *shah, 
-                          struct active_grant_entry *act,
-                          grant_status_t *status)
+                          domid_t  ldomid)
 {
     int      rc    = GNTST_okay;
     union grant_combo scombo;
@@ -648,10 +648,10 @@ static int _set_status_v2(domid_t  domid,
     if ( !act->pin &&
          ( (((flags & mask) != GTF_permit_access) &&
             ((flags & mask) != GTF_transitive)) ||
-          (id != domid)) )
+          (id != ldomid)) )
         PIN_FAIL(done, GNTST_general_error,
                  "Bad flags (%x) or dom (%d). (expected dom %d, flags %x)\n",
-                 flags, id, domid, mask);
+                 flags, id, ldomid, mask);
 
     if ( readonly )
     {
@@ -678,7 +678,7 @@ static int _set_status_v2(domid_t  domid,
     {
         if ( (((flags & mask) != GTF_permit_access) &&
               ((flags & mask) != GTF_transitive)) ||
-             (id != domid) ||
+             (id != ldomid) ||
              (!readonly && (flags & GTF_readonly)) )
         {
             gnttab_clear_flag(_GTF_writing, status);
@@ -686,7 +686,7 @@ static int _set_status_v2(domid_t  domid,
             PIN_FAIL(done, GNTST_general_error,
                      "Unstable flags (%x) or dom (%d). (expected dom %d) "
                      "(r/w: %d)\n",
-                     flags, id, domid, !readonly);
+                     flags, id, ldomid, !readonly);
         }
     }
     else
@@ -704,19 +704,19 @@ done:
 }
 
 
-static int _set_status(unsigned gt_version,
-                       domid_t  domid,
+static int _set_status(const grant_entry_header_t *shah,
+                       grant_status_t *status,
+                       unsigned rgt_version,
+                       struct active_grant_entry *act,
                        int readonly,
                        int mapflag,
-                       grant_entry_header_t *shah,
-                       struct active_grant_entry *act,
-                       grant_status_t *status)
+                       domid_t ldomid)
 {
 
-    if (gt_version == 1)
-        return _set_status_v1(domid, readonly, mapflag, shah, act);
+    if ( rgt_version == 1 )
+        return _set_status_v1(shah, act, readonly, mapflag, ldomid);
     else
-        return _set_status_v2(domid, readonly, mapflag, shah, act, status);
+        return _set_status_v2(shah, status, act, readonly, mapflag, ldomid);
 }
 
 static struct active_grant_entry *grant_map_exists(const struct domain *ld,
@@ -884,9 +884,9 @@ __gnttab_map_grant_ref(
          (!(op->flags & GNTMAP_readonly) &&
           !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask))) )
     {
-        if ( (rc = _set_status(rgt->gt_version, ld->domain_id,
-                               op->flags & GNTMAP_readonly,
-                               1, shah, act, status) ) != GNTST_okay )
+        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+                               op->flags & GNTMAP_readonly, 1,
+                               ld->domain_id) != GNTST_okay) )
             goto act_release_out;
 
         if ( !act->pin )
@@ -2258,8 +2258,8 @@ __acquire_grant_for_copy(
     {
         if ( (!old_pin || (!readonly &&
                            !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)))) &&
-             (rc = _set_status_v2(ldom, readonly, 0, shah, act,
-                                  status)) != GNTST_okay )
+             (rc = _set_status_v2(shah, status, act, readonly, 0,
+                                  ldom)) != GNTST_okay )
             goto unlock_out;
 
         if ( !allow_transitive )
@@ -2357,9 +2357,8 @@ __acquire_grant_for_copy(
     else if ( !old_pin ||
               (!readonly && !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask))) )
     {
-        if ( (rc = _set_status(rgt->gt_version, ldom,
-                               readonly, 0, shah, act,
-                               status) ) != GNTST_okay )
+        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+                               readonly, 0, ldom)) != GNTST_okay )
              goto unlock_out;
 
         td = rd;
-- 
2.17.1
xsa295/4.9-05.patch (application/octet-stream, 7.8 KB)
From 643ac676e190c17da348335b3bccd3cf11db4ab3 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:18 +0100
Subject: [PATCH v2 4.9 05/20] xen/arm64: bitops: Rewrite bitop helpers in C

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/README.LinuxPrimitives |  1 -
 xen/arch/arm/arm64/lib/bitops.S     | 67 ---------------------
 xen/arch/arm/arm64/lib/bitops.c     | 90 +++++++++++++++++++++++++++++
 3 files changed, 90 insertions(+), 68 deletions(-)
 delete mode 100644 xen/arch/arm/arm64/lib/bitops.S
 create mode 100644 xen/arch/arm/arm64/lib/bitops.c

diff --git a/xen/arch/arm/README.LinuxPrimitives b/xen/arch/arm/README.LinuxPrimitives
index 028e8721f9..891667a5da 100644
--- a/xen/arch/arm/README.LinuxPrimitives
+++ b/xen/arch/arm/README.LinuxPrimitives
@@ -8,7 +8,6 @@ arm64:
 
 bitops: last sync @ v3.16-rc6 (last commit: 8715466b6027)
 
-linux/arch/arm64/lib/bitops.S           xen/arch/arm/arm64/lib/bitops.S
 linux/arch/arm64/include/asm/bitops.h   xen/include/asm-arm/arm64/bitops.h
 
 ---------------------------------------------------------------------
diff --git a/xen/arch/arm/arm64/lib/bitops.S b/xen/arch/arm/arm64/lib/bitops.S
deleted file mode 100644
index 6471dd1875..0000000000
--- a/xen/arch/arm/arm64/lib/bitops.S
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Based on linux/arch/arm64/lib/bitops.h which in turn is
- * Based on arch/arm/lib/bitops.h
- *
- * Copyright (C) 2013 ARM Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * x0: bits 4:0  bit offset
- *     bits 31:5 word offset
- * x1: address
- */
-	.macro	bitop, name, instr
-ENTRY(	\name	)
-	and	w3, w0, #31		// Get bit offset
-	eor	w0, w0, w3		// Clear low bits
-	mov	x2, #1
-	add	x1, x1, x0, lsr #3	// Get word offset
-	lsl	x3, x2, x3		// Create mask
-1:	ldxr	w2, [x1]
-	\instr	w2, w2, w3
-	stxr	w0, w2, [x1]
-	cbnz	w0, 1b
-	ret
-ENDPROC(\name	)
-	.endm
-
-	.macro	testop, name, instr
-ENTRY(	\name	)
-	and	w3, w0, #31		// Get bit offset
-	eor	w0, w0, w3		// Clear low bits
-	mov	x2, #1
-	add	x1, x1, x0, lsr #3	// Get word offset
-	lsl	x4, x2, x3		// Create mask
-1:	ldxr	w2, [x1]
-	lsr	w0, w2, w3		// Save old value of bit
-	\instr	w2, w2, w4		// toggle bit
-	stlxr	w5, w2, [x1]
-	cbnz	w5, 1b
-	dmb	ish
-	and	w0, w0, #1
-3:	ret
-ENDPROC(\name	)
-	.endm
-
-/*
- * Atomic bit operations.
- */
-	bitop	change_bit, eor
-	bitop	clear_bit, bic
-	bitop	set_bit, orr
-
-	testop	test_and_change_bit, eor
-	testop	test_and_clear_bit, bic
-	testop	test_and_set_bit, orr
diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
new file mode 100644
index 0000000000..b1c681c642
--- /dev/null
+++ b/xen/arch/arm/arm64/lib/bitops.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/bitops.h>
+#include <asm/system.h>
+
+/*
+ * The atomic bit operations pass the number of bit in a signed number
+ * (not sure why). This has the drawback to increase the complexity of
+ * the resulting assembly.
+ *
+ * To generate simpler code, the number of bit (nr) will be cast to
+ * unsigned int.
+ *
+ * XXX: Rework the interface to use unsigned int.
+ */
+
+#define bitop(name, instr)                                                  \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
+    unsigned long res, tmp;                                                 \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldxr    %w2, %1\n"                                              \
+        "   " __stringify(instr) "     %w2, %w2, %w3\n"                     \
+        "   stxr    %w0, %w2, %1\n"                                         \
+        : "=&r" (res), "+Q" (*ptr), "=&r" (tmp)                             \
+        : "r" (mask));                                                      \
+    } while ( res );                                                        \
+}                                                                           \
+
+#define testop(name, instr)                                                 \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
+    const uint32_t mask = BIT_MASK(bit);                                    \
+    unsigned long res, tmp;                                                 \
+    unsigned long oldbit;                                                   \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldxr    %w3, %2\n"                                              \
+        "   lsr     %w1, %w3, %w5 // Save old value of bit\n"               \
+        "   " __stringify(instr) "  %w3, %w3, %w4 // Toggle bit\n"          \
+        "   stlxr   %w0, %w3, %2\n"                                         \
+        : "=&r" (res), "=&r" (oldbit), "+Q" (*ptr), "=&r" (tmp)             \
+        : "r" (mask), "r" (bit)                                             \
+        : "memory");                                                        \
+    } while ( res );                                                        \
+                                                                            \
+    dmb(ish);                                                               \
+                                                                            \
+    return oldbit & 1;                                                      \
+}
+
+bitop(change_bit, eor)
+bitop(clear_bit, bic)
+bitop(set_bit, orr)
+
+testop(test_and_change_bit, eor)
+testop(test_and_clear_bit, bic)
+testop(test_and_set_bit, orr)
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.17.1
xsa295/4.9-06.patch (application/octet-stream, 15.5 KB)
From 3ea9e7ad7946fd30f40276454a893ed3672d6a7a Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:19 +0100
Subject: [PATCH v2 4.9 06/20] xen/arm32: bitops: Rewrite bitop helpers in C

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/README.LinuxPrimitives    |  14 +---
 xen/arch/arm/arm32/lib/Makefile        |   5 +-
 xen/arch/arm/arm32/lib/bitops.c        |  98 +++++++++++++++++++++++
 xen/arch/arm/arm32/lib/bitops.h        | 104 -------------------------
 xen/arch/arm/arm32/lib/changebit.S     |  14 ----
 xen/arch/arm/arm32/lib/clearbit.S      |  14 ----
 xen/arch/arm/arm32/lib/setbit.S        |  15 ----
 xen/arch/arm/arm32/lib/testchangebit.S |  15 ----
 xen/arch/arm/arm32/lib/testclearbit.S  |  15 ----
 xen/arch/arm/arm32/lib/testsetbit.S    |  15 ----
 xen/include/asm-arm/arm32/bitops.h     |  19 ++---
 11 files changed, 108 insertions(+), 220 deletions(-)
 create mode 100644 xen/arch/arm/arm32/lib/bitops.c
 delete mode 100644 xen/arch/arm/arm32/lib/bitops.h
 delete mode 100644 xen/arch/arm/arm32/lib/changebit.S
 delete mode 100644 xen/arch/arm/arm32/lib/clearbit.S
 delete mode 100644 xen/arch/arm/arm32/lib/setbit.S
 delete mode 100644 xen/arch/arm/arm32/lib/testchangebit.S
 delete mode 100644 xen/arch/arm/arm32/lib/testclearbit.S
 delete mode 100644 xen/arch/arm/arm32/lib/testsetbit.S

diff --git a/xen/arch/arm/README.LinuxPrimitives b/xen/arch/arm/README.LinuxPrimitives
index 891667a5da..664a9f89ed 100644
--- a/xen/arch/arm/README.LinuxPrimitives
+++ b/xen/arch/arm/README.LinuxPrimitives
@@ -68,19 +68,9 @@ arm32
 
 bitops: last sync @ v3.16-rc6 (last commit: c32ffce0f66e)
 
-linux/arch/arm/lib/bitops.h             xen/arch/arm/arm32/lib/bitops.h
-linux/arch/arm/lib/changebit.S          xen/arch/arm/arm32/lib/changebit.S
-linux/arch/arm/lib/clearbit.S           xen/arch/arm/arm32/lib/clearbit.S
 linux/arch/arm/lib/findbit.S            xen/arch/arm/arm32/lib/findbit.S
-linux/arch/arm/lib/setbit.S             xen/arch/arm/arm32/lib/setbit.S
-linux/arch/arm/lib/testchangebit.S      xen/arch/arm/arm32/lib/testchangebit.S
-linux/arch/arm/lib/testclearbit.S       xen/arch/arm/arm32/lib/testclearbit.S
-linux/arch/arm/lib/testsetbit.S         xen/arch/arm/arm32/lib/testsetbit.S
-
-for i in bitops.h changebit.S clearbit.S findbit.S setbit.S testchangebit.S \
-         testclearbit.S testsetbit.S; do
-    diff -u ../linux/arch/arm/lib/$i xen/arch/arm/arm32/lib/$i;
-done
+
+diff -u ../linux/arch/arm/lib/findbit.S xen/arch/arm/arm32/lib/findbit.S
 
 ---------------------------------------------------------------------
 
diff --git a/xen/arch/arm/arm32/lib/Makefile b/xen/arch/arm/arm32/lib/Makefile
index e9fbc595b9..b1457c89dc 100644
--- a/xen/arch/arm/arm32/lib/Makefile
+++ b/xen/arch/arm/arm32/lib/Makefile
@@ -1,6 +1,5 @@
 obj-y += memcpy.o memmove.o memset.o memchr.o memzero.o
-obj-y += findbit.o setbit.o
-obj-y += setbit.o clearbit.o changebit.o
-obj-y += testsetbit.o testclearbit.o testchangebit.o
+obj-y += findbit.o
+obj-y += bitops.o
 obj-y += strchr.o strrchr.o
 obj-y += lib1funcs.o lshrdi3.o div64.o
diff --git a/xen/arch/arm/arm32/lib/bitops.c b/xen/arch/arm/arm32/lib/bitops.c
new file mode 100644
index 0000000000..c69bb53037
--- /dev/null
+++ b/xen/arch/arm/arm32/lib/bitops.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/bitops.h>
+#include <xen/prefetch.h>
+#include <asm/system.h>
+
+/*
+ * The atomic bit operations pass the number of bit in a signed number
+ * (not sure why). This has the drawback to increase the complexity of
+ * the resulting assembly.
+ *
+ * To generate simpler code, the number of bit (nr) will be cast to
+ * unsigned int.
+ *
+ * XXX: Rework the interface to use unsigned int.
+ */
+
+#define bitop(name, instr)                                                  \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
+    unsigned long res, tmp;                                                 \
+                                                                            \
+    ASSERT(((vaddr_t)p & 0x3) == 0);                                        \
+    prefetchw((const void *)ptr);                                           \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldrex   %2, %1\n"                                               \
+        "   " __stringify(instr) "     %2, %2, %3\n"                        \
+        "   strex   %0, %2, %1\n"                                           \
+        : "=&r" (res), "+Qo" (*ptr), "=&r" (tmp)                            \
+        : "r" (mask));                                                      \
+    } while ( res );                                                        \
+}
+
+#define testop(name, instr)                                                 \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
+    const uint32_t mask = BIT_MASK(bit);                                    \
+    unsigned long res, tmp;                                                 \
+    int oldbit;                                                             \
+                                                                            \
+    ASSERT(((vaddr_t)p & 0x3) == 0);                                        \
+    smp_mb();                                                               \
+                                                                            \
+    prefetchw((const void *)ptr);                                           \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldrex   %3, %2\n"                                               \
+        "   lsr     %1, %3, %5 // Save old value of bit\n"                  \
+        "   " __stringify(instr) "  %3, %3, %4 // Toggle bit\n"             \
+        "   strex  %0, %3, %2\n"                                            \
+        : "=&r" (res), "=&r" (oldbit), "+Qo" (*ptr), "=&r" (tmp)            \
+        : "r" (mask), "r" (bit));                                           \
+    } while ( res );                                                        \
+                                                                            \
+    smp_mb();                                                               \
+                                                                            \
+    return oldbit & 1;                                                      \
+}                                                                           \
+
+bitop(change_bit, eor)
+bitop(clear_bit, bic)
+bitop(set_bit, orr)
+
+testop(test_and_change_bit, eor)
+testop(test_and_clear_bit, bic)
+testop(test_and_set_bit, orr)
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/arm32/lib/bitops.h b/xen/arch/arm/arm32/lib/bitops.h
deleted file mode 100644
index d5e13476f4..0000000000
--- a/xen/arch/arm/arm32/lib/bitops.h
+++ /dev/null
@@ -1,104 +0,0 @@
-
-#if __LINUX_ARM_ARCH__ >= 6
-	.macro	bitop, name, instr
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	mov	r2, #1
-	and	r3, r0, #31		@ Get bit offset
-	mov	r0, r0, lsr #5
-	add	r1, r1, r0, lsl #2	@ Get word offset
-#if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
-	.arch_extension	mp
-	ALT_SMP(W(pldw)	[r1])
-	ALT_UP(W(nop))
-#endif
-	mov	r3, r2, lsl r3
-1:	ldrex	r2, [r1]
-	\instr	r2, r2, r3
-	strex	r0, r2, [r1]
-	cmp	r0, #0
-	bne	1b
-	bx	lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-
-	.macro	testop, name, instr, store
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	mov	r2, #1
-	and	r3, r0, #31		@ Get bit offset
-	mov	r0, r0, lsr #5
-	add	r1, r1, r0, lsl #2	@ Get word offset
-	mov	r3, r2, lsl r3		@ create mask
-	smp_dmb
-#if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
-	.arch_extension	mp
-	ALT_SMP(W(pldw)	[r1])
-	ALT_UP(W(nop))
-#endif
-1:	ldrex	r2, [r1]
-	ands	r0, r2, r3		@ save old value of bit
-	\instr	r2, r2, r3		@ toggle bit
-	strex	ip, r2, [r1]
-	cmp	ip, #0
-	bne	1b
-	smp_dmb
-	cmp	r0, #0
-	movne	r0, #1
-2:	bx	lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-#else
-	.macro	bitop, name, instr
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	and	r2, r0, #31
-	mov	r0, r0, lsr #5
-	mov	r3, #1
-	mov	r3, r3, lsl r2
-	save_and_disable_irqs ip
-	ldr	r2, [r1, r0, lsl #2]
-	\instr	r2, r2, r3
-	str	r2, [r1, r0, lsl #2]
-	restore_irqs ip
-	mov	pc, lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-
-/**
- * testop - implement a test_and_xxx_bit operation.
- * @instr: operational instruction
- * @store: store instruction
- *
- * Note: we can trivially conditionalise the store instruction
- * to avoid dirtying the data cache.
- */
-	.macro	testop, name, instr, store
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	and	r3, r0, #31
-	mov	r0, r0, lsr #5
-	save_and_disable_irqs ip
-	ldr	r2, [r1, r0, lsl #2]!
-	mov	r0, #1
-	tst	r2, r0, lsl r3
-	\instr	r2, r2, r0, lsl r3
-	\store	r2, [r1]
-	moveq	r0, #0
-	restore_irqs ip
-	mov	pc, lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-#endif
diff --git a/xen/arch/arm/arm32/lib/changebit.S b/xen/arch/arm/arm32/lib/changebit.S
deleted file mode 100644
index 6e4ae7594a..0000000000
--- a/xen/arch/arm/arm32/lib/changebit.S
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- *  linux/arch/arm/lib/changebit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-bitop	_change_bit, eor
diff --git a/xen/arch/arm/arm32/lib/clearbit.S b/xen/arch/arm/arm32/lib/clearbit.S
deleted file mode 100644
index fda553f246..0000000000
--- a/xen/arch/arm/arm32/lib/clearbit.S
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- *  linux/arch/arm/lib/clearbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-bitop	_clear_bit, bic
diff --git a/xen/arch/arm/arm32/lib/setbit.S b/xen/arch/arm/arm32/lib/setbit.S
deleted file mode 100644
index d52f0ab65c..0000000000
--- a/xen/arch/arm/arm32/lib/setbit.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- *  linux/arch/arm/lib/setbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "assembler.h"
-#include "bitops.h"
-	.text
-
-bitop	_set_bit, orr
diff --git a/xen/arch/arm/arm32/lib/testchangebit.S b/xen/arch/arm/arm32/lib/testchangebit.S
deleted file mode 100644
index d83b04c057..0000000000
--- a/xen/arch/arm/arm32/lib/testchangebit.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- *  linux/arch/arm/lib/testchangebit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-testop	_test_and_change_bit, eor, str
diff --git a/xen/arch/arm/arm32/lib/testclearbit.S b/xen/arch/arm/arm32/lib/testclearbit.S
deleted file mode 100644
index 6f5b7b92d1..0000000000
--- a/xen/arch/arm/arm32/lib/testclearbit.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- *  linux/arch/arm/lib/testclearbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-testop	_test_and_clear_bit, bicne, strne
diff --git a/xen/arch/arm/arm32/lib/testsetbit.S b/xen/arch/arm/arm32/lib/testsetbit.S
deleted file mode 100644
index 30425a842a..0000000000
--- a/xen/arch/arm/arm32/lib/testsetbit.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- *  linux/arch/arm/lib/testsetbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-testop	_test_and_set_bit, orreq, streq
diff --git a/xen/include/asm-arm/arm32/bitops.h b/xen/include/asm-arm/arm32/bitops.h
index 8be3564540..67c4c3f55c 100644
--- a/xen/include/asm-arm/arm32/bitops.h
+++ b/xen/include/asm-arm/arm32/bitops.h
@@ -1,19 +1,12 @@
 #ifndef _ARM_ARM32_BITOPS_H
 #define _ARM_ARM32_BITOPS_H
 
-extern void _set_bit(int nr, volatile void * p);
-extern void _clear_bit(int nr, volatile void * p);
-extern void _change_bit(int nr, volatile void * p);
-extern int _test_and_set_bit(int nr, volatile void * p);
-extern int _test_and_clear_bit(int nr, volatile void * p);
-extern int _test_and_change_bit(int nr, volatile void * p);
-
-#define set_bit(n,p)              _set_bit(n,p)
-#define clear_bit(n,p)            _clear_bit(n,p)
-#define change_bit(n,p)           _change_bit(n,p)
-#define test_and_set_bit(n,p)     _test_and_set_bit(n,p)
-#define test_and_clear_bit(n,p)   _test_and_clear_bit(n,p)
-#define test_and_change_bit(n,p)  _test_and_change_bit(n,p)
+extern void set_bit(int nr, volatile void * p);
+extern void clear_bit(int nr, volatile void * p);
+extern void change_bit(int nr, volatile void * p);
+extern int test_and_set_bit(int nr, volatile void * p);
+extern int test_and_clear_bit(int nr, volatile void * p);
+extern int test_and_change_bit(int nr, volatile void * p);
 
 #define flsl fls
 
-- 
2.17.1
xsa295/4.9-07.patch (application/octet-stream, 2.7 KB)
From ebe73e3bc357da771afc4f8a5d0babfd27f5730b Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:20 +0100
Subject: [PATCH v2 4.9 07/20] xen/arm: bitops: Consolidate prototypes in one
 place

The prototype are the same between arm32 and arm64. Consolidate them in
asm-arm/bitops.h.

This change will help the introductions of new helpers in a follow-up
patch.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm32/bitops.h |  7 -------
 xen/include/asm-arm/arm64/bitops.h | 10 ----------
 xen/include/asm-arm/bitops.h       |  8 ++++++++
 3 files changed, 8 insertions(+), 17 deletions(-)

diff --git a/xen/include/asm-arm/arm32/bitops.h b/xen/include/asm-arm/arm32/bitops.h
index 67c4c3f55c..57938a5874 100644
--- a/xen/include/asm-arm/arm32/bitops.h
+++ b/xen/include/asm-arm/arm32/bitops.h
@@ -1,13 +1,6 @@
 #ifndef _ARM_ARM32_BITOPS_H
 #define _ARM_ARM32_BITOPS_H
 
-extern void set_bit(int nr, volatile void * p);
-extern void clear_bit(int nr, volatile void * p);
-extern void change_bit(int nr, volatile void * p);
-extern int test_and_set_bit(int nr, volatile void * p);
-extern int test_and_clear_bit(int nr, volatile void * p);
-extern int test_and_change_bit(int nr, volatile void * p);
-
 #define flsl fls
 
 /*
diff --git a/xen/include/asm-arm/arm64/bitops.h b/xen/include/asm-arm/arm64/bitops.h
index 6bf1922680..6cc224ad13 100644
--- a/xen/include/asm-arm/arm64/bitops.h
+++ b/xen/include/asm-arm/arm64/bitops.h
@@ -1,16 +1,6 @@
 #ifndef _ARM_ARM64_BITOPS_H
 #define _ARM_ARM64_BITOPS_H
 
-/*
- * Little endian assembly atomic bitops.
- */
-extern void set_bit(int nr, volatile void *p);
-extern void clear_bit(int nr, volatile void *p);
-extern void change_bit(int nr, volatile void *p);
-extern int test_and_set_bit(int nr, volatile void *p);
-extern int test_and_clear_bit(int nr, volatile void *p);
-extern int test_and_change_bit(int nr, volatile void *p);
-
 /* Based on linux/include/asm-generic/bitops/builtin-__ffs.h */
 /**
  * __ffs - find first bit in word.
diff --git a/xen/include/asm-arm/bitops.h b/xen/include/asm-arm/bitops.h
index bda889841b..8e864b4456 100644
--- a/xen/include/asm-arm/bitops.h
+++ b/xen/include/asm-arm/bitops.h
@@ -37,6 +37,14 @@
 # error "unknown ARM variant"
 #endif
 
+/* Atomics bitops */
+void set_bit(int nr, volatile void *p);
+void clear_bit(int nr, volatile void *p);
+void change_bit(int nr, volatile void *p);
+int test_and_set_bit(int nr, volatile void *p);
+int test_and_clear_bit(int nr, volatile void *p);
+int test_and_change_bit(int nr, volatile void *p);
+
 /**
  * __test_and_set_bit - Set a bit and return its old value
  * @nr: Bit to set
-- 
2.17.1
xsa295/4.9-08.patch (application/octet-stream, 3.7 KB)
From f67c5cfdbfaed5eb51b4c3fb28a633aa4384d970 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Wed, 22 May 2019 13:37:53 -0700
Subject: [PATCH v2 4.9 08/20] xen/arm64: cmpxchg: Simplify the cmpxchg
 implementation

The only difference between each case of the cmpxchg is the size of
used. Rather than duplicating the code, provide a macro to generate each
cases.

This makes the code easier to read and modify.

This is part of XSA-295.

Signed-off-by; Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm64/cmpxchg.h | 98 +++++++++++------------------
 1 file changed, 36 insertions(+), 62 deletions(-)

diff --git a/xen/include/asm-arm/arm64/cmpxchg.h b/xen/include/asm-arm/arm64/cmpxchg.h
index ae42b2f5ff..393fbca6a5 100644
--- a/xen/include/asm-arm/arm64/cmpxchg.h
+++ b/xen/include/asm-arm/arm64/cmpxchg.h
@@ -61,80 +61,54 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
 	__ret; \
 })
 
-extern void __bad_cmpxchg(volatile void *ptr, int size);
+extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
+
+#define __CMPXCHG_CASE(w, sz, name)					\
+static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
+						  unsigned long old,	\
+						  unsigned long new)	\
+{									\
+	unsigned long res, oldval;					\
+									\
+	do {								\
+		asm volatile("// __cmpxchg_case_" #name "\n"		\
+		"	ldxr" #sz "	%" #w "1, %2\n"			\
+		"	mov	%w0, #0\n"				\
+		"	cmp	%" #w "1, %" #w "3\n"			\
+		"	b.ne	1f\n"					\
+		"	stxr" #sz "	%w0, %" #w "4, %2\n"		\
+		"1:\n"							\
+		: "=&r" (res), "=&r" (oldval),				\
+		  "+Q" (*(unsigned long *)ptr)				\
+		: "Ir" (old), "r" (new)					\
+		: "cc");						\
+	} while (res);							\
+									\
+	return oldval;							\
+}
+
+__CMPXCHG_CASE(w, b, 1)
+__CMPXCHG_CASE(w, h, 2)
+__CMPXCHG_CASE(w,  , 4)
+__CMPXCHG_CASE( ,  , 8)
 
 static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 				      unsigned long new, int size)
 {
-	unsigned long oldval = 0, res;
-
 	switch (size) {
 	case 1:
-		do {
-			asm volatile("// __cmpxchg1\n"
-			"	ldxrb	%w1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%w1, %w3\n"
-			"	b.ne	1f\n"
-			"	stxrb	%w0, %w4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u8 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_1(ptr, old, new);
 	case 2:
-		do {
-			asm volatile("// __cmpxchg2\n"
-			"	ldxrh	%w1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%w1, %w3\n"
-			"	b.ne	1f\n"
-			"	stxrh	%w0, %w4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u16 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_2(ptr, old, new);
 	case 4:
-		do {
-			asm volatile("// __cmpxchg4\n"
-			"	ldxr	%w1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%w1, %w3\n"
-			"	b.ne	1f\n"
-			"	stxr	%w0, %w4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u32 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_4(ptr, old, new);
 	case 8:
-		do {
-			asm volatile("// __cmpxchg8\n"
-			"	ldxr	%1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%1, %3\n"
-			"	b.ne	1f\n"
-			"	stxr	%w0, %4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u64 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_8(ptr, old, new);
 	default:
-		__bad_cmpxchg(ptr, size);
-		oldval = 0;
+		return __bad_cmpxchg(ptr, size);
 	}
 
-	return oldval;
+	ASSERT_UNREACHABLE();
 }
 
 static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
-- 
2.17.1
xsa295/4.9-09.patch (application/octet-stream, 3.6 KB)
From 1fc768848ad5f6e4e92152d85f495845d0504806 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:22 +0100
Subject: [PATCH v2 4.9 09/20] xen/arm32: cmpxchg: Simplify the cmpxchg
 implementation

The only difference between each case of the cmpxchg is the size of
used. Rather than duplicating the code, provide a macro to generate each
cases.

This makes the code easier to read and modify.

While doing the rework, the case for 64-bit cmpxchg is removed. This is
unused today (already commented) and it would not be possible to use
it directly.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm32/cmpxchg.h | 84 +++++++++++------------------
 1 file changed, 31 insertions(+), 53 deletions(-)

diff --git a/xen/include/asm-arm/arm32/cmpxchg.h b/xen/include/asm-arm/arm32/cmpxchg.h
index 03e0bed3a6..471a9e3a3f 100644
--- a/xen/include/asm-arm/arm32/cmpxchg.h
+++ b/xen/include/asm-arm/arm32/cmpxchg.h
@@ -52,72 +52,50 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
  * indicated by comparing RETURN with OLD.
  */
 
-extern void __bad_cmpxchg(volatile void *ptr, int size);
+extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
+
+#define __CMPXCHG_CASE(sz, name)					\
+static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
+						  unsigned long old,	\
+						  unsigned long new)	\
+{									\
+	unsigned long oldval, res;					\
+									\
+	do {								\
+		asm volatile("@ __cmpxchg_case_" #name "\n"		\
+		"	ldrex" #sz "	%1, [%2]\n"			\
+		"	mov	%0, #0\n"				\
+		"	teq	%1, %3\n"				\
+		"	strex" #sz "eq %0, %4, [%2]\n"			\
+		: "=&r" (res), "=&r" (oldval)				\
+		: "r" (ptr), "Ir" (old), "r" (new)			\
+		: "memory", "cc");					\
+	} while (res);							\
+									\
+	return oldval;							\
+}
+
+__CMPXCHG_CASE(b, 1)
+__CMPXCHG_CASE(h, 2)
+__CMPXCHG_CASE( , 4)
 
 static always_inline unsigned long __cmpxchg(
     volatile void *ptr, unsigned long old, unsigned long new, int size)
 {
-	unsigned long oldval, res;
-
 	prefetchw((const void *)ptr);
 
 	switch (size) {
 	case 1:
-		do {
-			asm volatile("@ __cmpxchg1\n"
-			"	ldrexb	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexbeq %0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-		} while (res);
-		break;
+		return __cmpxchg_case_1(ptr, old, new);
 	case 2:
-		do {
-			asm volatile("@ __cmpxchg2\n"
-			"	ldrexh	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexheq %0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-		} while (res);
-		break;
+		return __cmpxchg_case_2(ptr, old, new);
 	case 4:
-		do {
-			asm volatile("@ __cmpxchg4\n"
-			"	ldrex	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexeq	%0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-	    } while (res);
-	    break;
-#if 0
-	case 8:
-		do {
-			asm volatile("@ __cmpxchg8\n"
-			"	ldrexd	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexdeq %0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-		} while (res);
-		break;
-#endif
+		return __cmpxchg_case_4(ptr, old, new);
 	default:
-		__bad_cmpxchg(ptr, size);
-		oldval = 0;
+		return __bad_cmpxchg(ptr, size);
 	}
 
-	return oldval;
+	ASSERT_UNREACHABLE();
 }
 
 static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
-- 
2.17.1
xsa295/4.9-10.patch (application/octet-stream, 15.3 KB)
From 9cfe88d37e0c02b7fbe04ef0a93bab59dc8071b2 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:23 +0100
Subject: [PATCH v2 4.9 10/20] xen/arm: bitops: Implement a new set of helpers
 that can timeout

Exclusive load-store atomics should only be used between trusted
threads. As not all the guests are trusted, it may be possible to DoS
Xen when updating shared memory with guest atomically.

To prevent the infinite loop, we introduce a new set of helpers that can
timeout. The timeout is based on the maximum number of iterations.

They will be used in follow-up patch to make atomic operations
on shared memory safe.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/arm32/lib/bitops.c | 52 ++++++++++++++++++++++++++++-----
 xen/arch/arm/arm64/lib/bitops.c | 52 ++++++++++++++++++++++++++++-----
 xen/include/asm-arm/bitops.h    | 28 +++++++++++++++++-
 3 files changed, 117 insertions(+), 15 deletions(-)

diff --git a/xen/arch/arm/arm32/lib/bitops.c b/xen/arch/arm/arm32/lib/bitops.c
index c69bb53037..08750314fc 100644
--- a/xen/arch/arm/arm32/lib/bitops.c
+++ b/xen/arch/arm/arm32/lib/bitops.c
@@ -30,7 +30,8 @@
  */
 
 #define bitop(name, instr)                                                  \
-void name(int nr, volatile void *p)                                         \
+static always_inline bool int_##name(int nr, volatile void *p, bool timeout,\
+                                     unsigned int max_try)                  \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
@@ -47,17 +48,33 @@ void name(int nr, volatile void *p)                                         \
         "   strex   %0, %2, %1\n"                                           \
         : "=&r" (res), "+Qo" (*ptr), "=&r" (tmp)                            \
         : "r" (mask));                                                      \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
+                                                                            \
+    return !res;                                                            \
+}                                                                           \
+                                                                            \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    if ( !int_##name(nr, p, false, 0) )                                     \
+        ASSERT_UNREACHABLE();                                               \
+}                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p, unsigned int max_try)         \
+{                                                                           \
+    return int_##name(nr, p, true, max_try);                                \
 }
 
 #define testop(name, instr)                                                 \
-int name(int nr, volatile void *p)                                          \
+static always_inline bool int_##name(int nr, volatile void *p, int *oldbit, \
+                                     bool timeout, unsigned int max_try)    \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
     const uint32_t mask = BIT_MASK(bit);                                    \
     unsigned long res, tmp;                                                 \
-    int oldbit;                                                             \
                                                                             \
     ASSERT(((vaddr_t)p & 0x3) == 0);                                        \
     smp_mb();                                                               \
@@ -71,14 +88,35 @@ int name(int nr, volatile void *p)                                          \
         "   lsr     %1, %3, %5 // Save old value of bit\n"                  \
         "   " __stringify(instr) "  %3, %3, %4 // Toggle bit\n"             \
         "   strex  %0, %3, %2\n"                                            \
-        : "=&r" (res), "=&r" (oldbit), "+Qo" (*ptr), "=&r" (tmp)            \
+        : "=&r" (res), "=&r" (*oldbit), "+Qo" (*ptr), "=&r" (tmp)           \
         : "r" (mask), "r" (bit));                                           \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
                                                                             \
     smp_mb();                                                               \
                                                                             \
-    return oldbit & 1;                                                      \
+    *oldbit &= 1;                                                           \
+                                                                            \
+    return !res;                                                            \
+}                                                                           \
+                                                                            \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    int oldbit;                                                             \
+                                                                            \
+    if ( !int_##name(nr, p, &oldbit, false, 0) )                            \
+        ASSERT_UNREACHABLE();                                               \
+                                                                            \
+    return oldbit;                                                          \
 }                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p,                               \
+                    int *oldbit, unsigned int max_try)                      \
+{                                                                           \
+    return int_##name(nr, p, oldbit, true, max_try);                        \
+}
 
 bitop(change_bit, eor)
 bitop(clear_bit, bic)
diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
index b1c681c642..78bf4ed8c5 100644
--- a/xen/arch/arm/arm64/lib/bitops.c
+++ b/xen/arch/arm/arm64/lib/bitops.c
@@ -29,7 +29,8 @@
  */
 
 #define bitop(name, instr)                                                  \
-void name(int nr, volatile void *p)                                         \
+static always_inline bool int_##name(int nr, volatile void *p, bool timeout,\
+                                     unsigned int max_try)                  \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
@@ -43,17 +44,33 @@ void name(int nr, volatile void *p)                                         \
         "   stxr    %w0, %w2, %1\n"                                         \
         : "=&r" (res), "+Q" (*ptr), "=&r" (tmp)                             \
         : "r" (mask));                                                      \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
+                                                                            \
+    return !res;                                                            \
 }                                                                           \
+                                                                            \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    if ( !int_##name(nr, p, false, 0) )                                     \
+        ASSERT_UNREACHABLE();                                               \
+}                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p, unsigned int max_try)         \
+{                                                                           \
+    return int_##name(nr, p, true, max_try);                                \
+}
 
 #define testop(name, instr)                                                 \
-int name(int nr, volatile void *p)                                          \
+static always_inline bool int_##name(int nr, volatile void *p, int *oldbit, \
+                                     bool timeout, unsigned int max_try)    \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
     const uint32_t mask = BIT_MASK(bit);                                    \
     unsigned long res, tmp;                                                 \
-    unsigned long oldbit;                                                   \
                                                                             \
     do                                                                      \
     {                                                                       \
@@ -62,14 +79,35 @@ int name(int nr, volatile void *p)                                          \
         "   lsr     %w1, %w3, %w5 // Save old value of bit\n"               \
         "   " __stringify(instr) "  %w3, %w3, %w4 // Toggle bit\n"          \
         "   stlxr   %w0, %w3, %2\n"                                         \
-        : "=&r" (res), "=&r" (oldbit), "+Q" (*ptr), "=&r" (tmp)             \
+        : "=&r" (res), "=&r" (*oldbit), "+Q" (*ptr), "=&r" (tmp)            \
         : "r" (mask), "r" (bit)                                             \
         : "memory");                                                        \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
                                                                             \
     dmb(ish);                                                               \
                                                                             \
-    return oldbit & 1;                                                      \
+    *oldbit &= 1;                                                           \
+                                                                            \
+    return !res;                                                            \
+}                                                                           \
+                                                                            \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    int oldbit;                                                             \
+                                                                            \
+    if ( !int_##name(nr, p, &oldbit, false, 0) )                            \
+        ASSERT_UNREACHABLE();                                               \
+                                                                            \
+    return oldbit;                                                          \
+}                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p,                               \
+                    int *oldbit, unsigned int max_try)                      \
+{                                                                           \
+    return int_##name(nr, p, oldbit, true, max_try);                        \
 }
 
 bitop(change_bit, eor)
diff --git a/xen/include/asm-arm/bitops.h b/xen/include/asm-arm/bitops.h
index 8e864b4456..172bbaee7e 100644
--- a/xen/include/asm-arm/bitops.h
+++ b/xen/include/asm-arm/bitops.h
@@ -37,7 +37,14 @@
 # error "unknown ARM variant"
 #endif
 
-/* Atomics bitops */
+/*
+ * Atomic bitops
+ *
+ * The helpers below *should* only be used on memory shared between
+ * trusted threads or we know the memory cannot be accessed by another
+ * thread.
+ */
+
 void set_bit(int nr, volatile void *p);
 void clear_bit(int nr, volatile void *p);
 void change_bit(int nr, volatile void *p);
@@ -45,6 +52,25 @@ int test_and_set_bit(int nr, volatile void *p);
 int test_and_clear_bit(int nr, volatile void *p);
 int test_and_change_bit(int nr, volatile void *p);
 
+/*
+ * The helpers below may fail to update the memory if the action takes
+ * too long.
+ *
+ * @max_try: Maximum number of iterations
+ *
+ * The helpers will return true when the update has succeeded (i.e no
+ * timeout) and false if the update has failed.
+ */
+bool set_bit_timeout(int nr, volatile void *p, unsigned int max_try);
+bool clear_bit_timeout(int nr, volatile void *p, unsigned int max_try);
+bool change_bit_timeout(int nr, volatile void *p, unsigned int max_try);
+bool test_and_set_bit_timeout(int nr, volatile void *p,
+                              int *oldbit, unsigned int max_try);
+bool test_and_clear_bit_timeout(int nr, volatile void *p,
+                                int *oldbit, unsigned int max_try);
+bool test_and_change_bit_timeout(int nr, volatile void *p,
+                                 int *oldbit, unsigned int max_try);
+
 /**
  * __test_and_set_bit - Set a bit and return its old value
  * @nr: Bit to set
-- 
2.17.1
xsa295/4.9-11.patch (application/octet-stream, 8.3 KB)
From ef9c5ec0a2eda80fd611cabf955cb1b43a3499c7 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Wed, 22 May 2019 13:39:17 -0700
Subject: [PATCH v2 4.9 11/20] xen/arm: cmpxchg: Provide a new helper that can
 timeout

Exclusive load-store atomics should only be used between trusted
threads. As not all the guests are trusted, it may be possible to DoS
Xen when updating shared memory with guest atomically.

To prevent the infinite loop, we introduce a new helper that can timeout.
The timeout is based on the maximum number of iterations.

It will be used in follow-up patch to make atomic operations on shared
memory safe.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm32/cmpxchg.h | 63 +++++++++++++++++++++-----
 xen/include/asm-arm/arm64/cmpxchg.h | 70 ++++++++++++++++++++++-------
 2 files changed, 106 insertions(+), 27 deletions(-)

diff --git a/xen/include/asm-arm/arm32/cmpxchg.h b/xen/include/asm-arm/arm32/cmpxchg.h
index 471a9e3a3f..49ca2a0d7a 100644
--- a/xen/include/asm-arm/arm32/cmpxchg.h
+++ b/xen/include/asm-arm/arm32/cmpxchg.h
@@ -55,11 +55,14 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
 extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
 
 #define __CMPXCHG_CASE(sz, name)					\
-static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
-						  unsigned long old,	\
-						  unsigned long new)	\
+static inline bool __cmpxchg_case_##name(volatile void *ptr,		\
+					 unsigned long *old,		\
+					 unsigned long new,		\
+					 bool timeout,			\
+					 unsigned int max_try)		\
 {									\
-	unsigned long oldval, res;					\
+	unsigned long oldval;						\
+	unsigned long res;						\
 									\
 	do {								\
 		asm volatile("@ __cmpxchg_case_" #name "\n"		\
@@ -68,29 +71,35 @@ static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
 		"	teq	%1, %3\n"				\
 		"	strex" #sz "eq %0, %4, [%2]\n"			\
 		: "=&r" (res), "=&r" (oldval)				\
-		: "r" (ptr), "Ir" (old), "r" (new)			\
+		: "r" (ptr), "Ir" (*old), "r" (new)			\
 		: "memory", "cc");					\
-	} while (res);							\
 									\
-	return oldval;							\
+		if (!res)						\
+			break;						\
+	} while (!timeout || ((--max_try) > 0));			\
+									\
+	*old = oldval;							\
+									\
+	return !res;							\
 }
 
 __CMPXCHG_CASE(b, 1)
 __CMPXCHG_CASE(h, 2)
 __CMPXCHG_CASE( , 4)
 
-static always_inline unsigned long __cmpxchg(
-    volatile void *ptr, unsigned long old, unsigned long new, int size)
+static always_inline bool __int_cmpxchg(volatile void *ptr, unsigned long *old,
+					unsigned long new, int size,
+					bool timeout, unsigned int max_try)
 {
 	prefetchw((const void *)ptr);
 
 	switch (size) {
 	case 1:
-		return __cmpxchg_case_1(ptr, old, new);
+		return __cmpxchg_case_1(ptr, old, new, timeout, max_try);
 	case 2:
-		return __cmpxchg_case_2(ptr, old, new);
+		return __cmpxchg_case_2(ptr, old, new, timeout, max_try);
 	case 4:
-		return __cmpxchg_case_4(ptr, old, new);
+		return __cmpxchg_case_4(ptr, old, new, timeout, max_try);
 	default:
 		return __bad_cmpxchg(ptr, size);
 	}
@@ -98,6 +107,17 @@ static always_inline unsigned long __cmpxchg(
 	ASSERT_UNREACHABLE();
 }
 
+static always_inline unsigned long __cmpxchg(volatile void *ptr,
+					     unsigned long old,
+					     unsigned long new,
+					     int size)
+{
+	if (!__int_cmpxchg(ptr, &old, new, size, false, 0))
+		ASSERT_UNREACHABLE();
+
+	return old;
+}
+
 static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
                                                 unsigned long old,
                                                 unsigned long new, int size)
@@ -111,6 +131,25 @@ static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
 	return ret;
 }
 
+/*
+ * The helper may fail to update the memory if the action takes too long.
+ *
+ * @old: On call the value pointed contains the expected old value. It will be
+ * updated to the actual old value.
+ * @max_try: Maximum number of iterations
+ *
+ * The helper will return true when the update has succeeded (i.e no
+ * timeout) and false if the update has failed.
+ */
+static always_inline bool __cmpxchg_mb_timeout(volatile void *ptr,
+					       unsigned long *old,
+					       unsigned long new,
+					       int size,
+					       unsigned int max_try)
+{
+	return __int_cmpxchg(ptr, old, new, size, true, max_try);
+}
+
 #define cmpxchg(ptr,o,n)						\
 	((__typeof__(*(ptr)))__cmpxchg_mb((ptr),			\
 					  (unsigned long)(o),		\
diff --git a/xen/include/asm-arm/arm64/cmpxchg.h b/xen/include/asm-arm/arm64/cmpxchg.h
index 393fbca6a5..5bc2e1f786 100644
--- a/xen/include/asm-arm/arm64/cmpxchg.h
+++ b/xen/include/asm-arm/arm64/cmpxchg.h
@@ -64,11 +64,14 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
 extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
 
 #define __CMPXCHG_CASE(w, sz, name)					\
-static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
-						  unsigned long old,	\
-						  unsigned long new)	\
+static inline bool __cmpxchg_case_##name(volatile void *ptr,		\
+					 unsigned long *old,		\
+					 unsigned long new,		\
+					 bool timeout,			\
+					 unsigned int max_try)		\
 {									\
-	unsigned long res, oldval;					\
+	unsigned long oldval;						\
+	unsigned long res;						\
 									\
 	do {								\
 		asm volatile("// __cmpxchg_case_" #name "\n"		\
@@ -80,11 +83,16 @@ static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
 		"1:\n"							\
 		: "=&r" (res), "=&r" (oldval),				\
 		  "+Q" (*(unsigned long *)ptr)				\
-		: "Ir" (old), "r" (new)					\
+		: "Ir" (*old), "r" (new)				\
 		: "cc");						\
-	} while (res);							\
 									\
-	return oldval;							\
+		if (!res)						\
+			break;						\
+	} while (!timeout || ((--max_try) > 0));			\
+									\
+	*old = oldval;							\
+									\
+	return !res;							\
 }
 
 __CMPXCHG_CASE(w, b, 1)
@@ -92,18 +100,19 @@ __CMPXCHG_CASE(w, h, 2)
 __CMPXCHG_CASE(w,  , 4)
 __CMPXCHG_CASE( ,  , 8)
 
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
-				      unsigned long new, int size)
+static always_inline bool __int_cmpxchg(volatile void *ptr, unsigned long *old,
+					unsigned long new, int size,
+					bool timeout, unsigned int max_try)
 {
 	switch (size) {
 	case 1:
-		return __cmpxchg_case_1(ptr, old, new);
+		return __cmpxchg_case_1(ptr, old, new, timeout, max_try);
 	case 2:
-		return __cmpxchg_case_2(ptr, old, new);
+		return __cmpxchg_case_2(ptr, old, new, timeout, max_try);
 	case 4:
-		return __cmpxchg_case_4(ptr, old, new);
+		return __cmpxchg_case_4(ptr, old, new, timeout, max_try);
 	case 8:
-		return __cmpxchg_case_8(ptr, old, new);
+		return __cmpxchg_case_8(ptr, old, new, timeout, max_try);
 	default:
 		return __bad_cmpxchg(ptr, size);
 	}
@@ -111,8 +120,20 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 	ASSERT_UNREACHABLE();
 }
 
-static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
-					 unsigned long new, int size)
+static always_inline unsigned long __cmpxchg(volatile void *ptr,
+					     unsigned long old,
+					     unsigned long new,
+					     int size)
+{
+	if (!__int_cmpxchg(ptr, &old, new, size, false, 0))
+		ASSERT_UNREACHABLE();
+
+	return old;
+}
+
+static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
+						unsigned long old,
+						unsigned long new, int size)
 {
 	unsigned long ret;
 
@@ -123,6 +144,25 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
 	return ret;
 }
 
+/*
+ * The helper may fail to update the memory if the action takes too long.
+ *
+ * @old: On call the value pointed contains the expected old value. It will be
+ * updated to the actual old value.
+ * @max_try: Maximum number of iterations
+ *
+ * The helper will return true when the update has succeeded (i.e no
+ * timeout) and false if the update has failed.
+ */
+static always_inline bool __cmpxchg_mb_timeout(volatile void *ptr,
+					       unsigned long *old,
+					       unsigned long new,
+					       int size,
+					       unsigned int max_try)
+{
+	return __int_cmpxchg(ptr, old, new, size, true, max_try);
+}
+
 #define cmpxchg(ptr, o, n) \
 ({ \
 	__typeof__(*(ptr)) __ret; \
-- 
2.17.1
xsa295/4.9-12.patch (application/octet-stream, 806 B)
From dc77d65c8554c2dbc00d3e4f73f8ee3bc8380c77 Mon Sep 17 00:00:00 2001
From: Xin Li <[email protected]>
Date: Tue, 9 Oct 2018 17:33:18 +0800
Subject: [PATCH v2 4.9 12/20] xen/xsm: remove unnecessary #define

this #define is unnecessary since XSM_INLINE is redefined in
xsm/dummy.h, it's a risk of build breakage, so remove it.

Signed-off-by: Xin Li <[email protected]>
Reviewed-by: Jan Beulich <[email protected]>
Acked-by: Daniel De Graaf <[email protected]>
---
 xen/xsm/dummy.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c
index 3cb5492dd3..667078ea07 100644
--- a/xen/xsm/dummy.c
+++ b/xen/xsm/dummy.c
@@ -11,7 +11,6 @@
  */
 
 #define XSM_NO_WRAPPERS
-#define XSM_INLINE /* */
 #include <xsm/dummy.h>
 
 struct xsm_operations dummy_xsm_ops;
-- 
2.17.1
xsa295/4.9-13.patch (application/octet-stream, 3.8 KB)
From 2dcc47b84909a4116bd82039055bf66eff878fda Mon Sep 17 00:00:00 2001
From: Xin Li <[email protected]>
Date: Tue, 9 Oct 2018 17:33:19 +0800
Subject: [PATCH v2 4.9 13/20] xen/xsm: Introduce new boot parameter xsm

Introduce new boot parameter xsm to choose which xsm module is enabled,
and set default to dummy. And add new option in Kconfig to choose the
default XSM implementation.

Signed-off-by: Xin Li <[email protected]>
Acked-by: Daniel De Graaf <[email protected]>
Acked-by: Andrew Cooper <[email protected]>
---
 docs/misc/xen-command-line.markdown | 13 +++++++++
 xen/common/Kconfig                  | 13 ++++++++-
 xen/xsm/xsm_core.c                  | 44 ++++++++++++++++++++++++++++-
 3 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/docs/misc/xen-command-line.markdown b/docs/misc/xen-command-line.markdown
index 85226212a9..d03830f837 100644
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -790,6 +790,19 @@ hardware domain is architecture dependent.
 Note that specifying zero as domU value means zero, while for dom0 it means
 to use the default.
 
+### xsm
+> `= dummy | flask`
+
+> Default: `dummy`
+
+Specify which XSM module should be enabled.  This option is only available if
+the hypervisor was compiled with XSM support.
+
+* `dummy`: this is the default choice.  Basic restriction for common deployment
+  (the dummy module) will be applied.  It's also used when XSM is compiled out.
+* `flask`: this is the policy based access control.  To choose this, the
+  separated option in kconfig must also be enabled.
+
 ### flask
 > `= permissive | enforcing | late | disabled`
 
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index dc8e876439..c87422282f 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -99,7 +99,7 @@ config XSM
 
 config FLASK
 	def_bool y
-	prompt "FLux Advanced Security Kernel support" if EXPERT = "y"
+	prompt "FLux Advanced Security Kernel support"
 	depends on XSM
 	---help---
 	  Enables FLASK (FLux Advanced Security Kernel) as the access control
@@ -137,6 +137,17 @@ config XSM_POLICY
 
 	  If unsure, say Y.
 
+choice
+	prompt "Default XSM implementation"
+	depends on XSM
+	default XSM_FLASK_DEFAULT if XSM_FLASK
+	default XSM_DUMMY_DEFAULT
+	config XSM_DUMMY_DEFAULT
+		bool "Match non-XSM behavior"
+	config XSM_FLASK_DEFAULT
+		bool "FLux Advanced Security Kernel" if XSM_FLASK
+endchoice
+
 config LATE_HWDOM
 	bool "Dedicated hardware domain"
 	default n
diff --git a/xen/xsm/xsm_core.c b/xen/xsm/xsm_core.c
index 08994ee7a1..e78f7d8ca2 100644
--- a/xen/xsm/xsm_core.c
+++ b/xen/xsm/xsm_core.c
@@ -27,6 +27,35 @@
 
 struct xsm_operations *xsm_ops;
 
+enum xsm_bootparam {
+    XSM_BOOTPARAM_DUMMY,
+    XSM_BOOTPARAM_FLASK,
+};
+
+static enum xsm_bootparam __initdata xsm_bootparam =
+#ifdef CONFIG_XSM_FLASK_DEFAULT
+    XSM_BOOTPARAM_FLASK;
+#else
+    XSM_BOOTPARAM_DUMMY;
+#endif
+
+static int __init parse_xsm_param(const char *s)
+{
+    int rc = 0;
+
+    if ( !strcmp(s, "dummy") )
+        xsm_bootparam = XSM_BOOTPARAM_DUMMY;
+#ifdef CONFIG_XSM_FLASK
+    else if ( !strcmp(s, "flask") )
+        xsm_bootparam = XSM_BOOTPARAM_FLASK;
+#endif
+    else
+        rc = -EINVAL;
+
+    return rc;
+}
+custom_param("xsm", parse_xsm_param);
+
 static inline int verify(struct xsm_operations *ops)
 {
     /* verify the security_operations structure exists */
@@ -53,7 +82,20 @@ static int __init xsm_core_init(const void *policy_buffer, size_t policy_size)
     }
 
     xsm_ops = &dummy_xsm_ops;
-    flask_init(policy_buffer, policy_size);
+
+    switch ( xsm_bootparam )
+    {
+    case XSM_BOOTPARAM_DUMMY:
+        break;
+
+    case XSM_BOOTPARAM_FLASK:
+        flask_init(policy_buffer, policy_size);
+        break;
+
+    default:
+        ASSERT_UNREACHABLE();
+        break;
+    }
 
     return 0;
 }
-- 
2.17.1
xsa295/4.9-14.patch (application/octet-stream, 8.3 KB)
From 44223901fb315157f7194eb9de20a0758ab5618c Mon Sep 17 00:00:00 2001
From: Xin Li <[email protected]>
Date: Tue, 9 Oct 2018 17:33:20 +0800
Subject: [PATCH v2 4.9 14/20] xen/xsm: Add new SILO mode for XSM

When SILO is enabled, there would be no page-sharing or event notifications
between unprivileged VMs (no grant tables or event channels).

Signed-off-by: Xin Li <[email protected]>
Acked-by: Daniel De Graaf <[email protected]>
Acked-by: Andrew Cooper <[email protected]>
---
 docs/misc/xen-command-line.markdown |   5 +-
 xen/common/Kconfig                  |  15 ++++
 xen/include/xsm/dummy.h             |   3 +-
 xen/include/xsm/xsm.h               |   6 ++
 xen/xsm/Makefile                    |   1 +
 xen/xsm/silo.c                      | 108 ++++++++++++++++++++++++++++
 xen/xsm/xsm_core.c                  |  11 +++
 7 files changed, 147 insertions(+), 2 deletions(-)
 create mode 100644 xen/xsm/silo.c

diff --git a/docs/misc/xen-command-line.markdown b/docs/misc/xen-command-line.markdown
index d03830f837..a3194cadc3 100644
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -791,7 +791,7 @@ Note that specifying zero as domU value means zero, while for dom0 it means
 to use the default.
 
 ### xsm
-> `= dummy | flask`
+> `= dummy | flask | silo`
 
 > Default: `dummy`
 
@@ -802,6 +802,9 @@ the hypervisor was compiled with XSM support.
   (the dummy module) will be applied.  It's also used when XSM is compiled out.
 * `flask`: this is the policy based access control.  To choose this, the
   separated option in kconfig must also be enabled.
+* `silo`: this will deny any unmediated communication channels between
+  unprivileged VMs.  To choose this, the separated option in kconfig must also
+  be enabled.
 
 ### flask
 > `= permissive | enforcing | late | disabled`
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index c87422282f..c129cfbdc2 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -137,15 +137,30 @@ config XSM_POLICY
 
 	  If unsure, say Y.
 
+config XSM_SILO
+	def_bool y
+	prompt "SILO support"
+	depends on XSM
+	---help---
+	  Enables SILO as the access control mechanism used by the XSM framework.
+	  This is not the default module, add boot parameter xsm=silo to choose
+	  it. This will deny any unmediated communication channels (grant tables
+	  and event channels) between unprivileged VMs.
+
+	  If unsure, say Y.
+
 choice
 	prompt "Default XSM implementation"
 	depends on XSM
 	default XSM_FLASK_DEFAULT if XSM_FLASK
+	default XSM_SILO_DEFAULT if XSM_SILO
 	default XSM_DUMMY_DEFAULT
 	config XSM_DUMMY_DEFAULT
 		bool "Match non-XSM behavior"
 	config XSM_FLASK_DEFAULT
 		bool "FLux Advanced Security Kernel" if XSM_FLASK
+	config XSM_SILO_DEFAULT
+		bool "SILO" if XSM_SILO
 endchoice
 
 config LATE_HWDOM
diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h
index b565a02d44..a25ce30a8a 100644
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -34,7 +34,8 @@ void __xsm_action_mismatch_detected(void);
  * There is no xsm_default_t argument available, so the value from the assertion
  * is used to initialize the variable.
  */
-#define XSM_INLINE /* */
+#define XSM_INLINE __maybe_unused
+
 #define XSM_DEFAULT_ARG /* */
 #define XSM_DEFAULT_VOID void
 #define XSM_ASSERT_ACTION(def) xsm_default_t action = def; (void)action
diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h
index 60c0fd6a62..ef6ff3a786 100644
--- a/xen/include/xsm/xsm.h
+++ b/xen/include/xsm/xsm.h
@@ -742,6 +742,12 @@ extern const unsigned char xsm_init_policy[];
 extern const unsigned int xsm_init_policy_size;
 #endif
 
+#ifdef CONFIG_XSM_SILO
+extern void silo_init(void);
+#else
+static inline void silo_init(void) {}
+#endif
+
 #else /* CONFIG_XSM */
 
 #include <xsm/dummy.h>
diff --git a/xen/xsm/Makefile b/xen/xsm/Makefile
index 3252c46e64..50e21303b3 100644
--- a/xen/xsm/Makefile
+++ b/xen/xsm/Makefile
@@ -1,5 +1,6 @@
 obj-y += xsm_core.o
 obj-$(CONFIG_XSM) += xsm_policy.o
 obj-$(CONFIG_XSM) += dummy.o
+obj-$(CONFIG_XSM_SILO) += silo.o
 
 subdir-$(CONFIG_FLASK) += flask
diff --git a/xen/xsm/silo.c b/xen/xsm/silo.c
new file mode 100644
index 0000000000..4850756a3d
--- /dev/null
+++ b/xen/xsm/silo.c
@@ -0,0 +1,108 @@
+/******************************************************************************
+ * xsm/silo.c
+ *
+ * SILO module for XSM (Xen Security Modules)
+ *
+ * Copyright (c) 2018 Citrix Systems Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+#define XSM_NO_WRAPPERS
+#include <xsm/dummy.h>
+
+/*
+ * Check if inter-domain communication is allowed.
+ * Return true when pass check.
+ */
+static bool silo_mode_dom_check(const struct domain *ldom,
+                                const struct domain *rdom)
+{
+    const struct domain *currd = current->domain;
+
+    return (is_control_domain(currd) || is_control_domain(ldom) ||
+            is_control_domain(rdom) || ldom == rdom);
+}
+
+static int silo_evtchn_unbound(struct domain *d1, struct evtchn *chn,
+                               domid_t id2)
+{
+    int rc = -EPERM;
+    struct domain *d2 = rcu_lock_domain_by_any_id(id2);
+
+    if ( d2 == NULL )
+        rc = -ESRCH;
+    else
+    {
+        if ( silo_mode_dom_check(d1, d2) )
+            rc = xsm_evtchn_unbound(d1, chn, id2);
+        rcu_unlock_domain(d2);
+    }
+
+    return rc;
+}
+
+static int silo_evtchn_interdomain(struct domain *d1, struct evtchn *chan1,
+                                   struct domain *d2, struct evtchn *chan2)
+{
+    if ( silo_mode_dom_check(d1, d2) )
+        return xsm_evtchn_interdomain(d1, chan1, d2, chan2);
+    return -EPERM;
+}
+
+static int silo_grant_mapref(struct domain *d1, struct domain *d2,
+                             uint32_t flags)
+{
+    if ( silo_mode_dom_check(d1, d2) )
+        return xsm_grant_mapref(d1, d2, flags);
+    return -EPERM;
+}
+
+static int silo_grant_transfer(struct domain *d1, struct domain *d2)
+{
+    if ( silo_mode_dom_check(d1, d2) )
+        return xsm_grant_transfer(d1, d2);
+    return -EPERM;
+}
+
+static int silo_grant_copy(struct domain *d1, struct domain *d2)
+{
+    if ( silo_mode_dom_check(d1, d2) )
+        return xsm_grant_copy(d1, d2);
+    return -EPERM;
+}
+
+static struct xsm_operations silo_xsm_ops = {
+    .evtchn_unbound = silo_evtchn_unbound,
+    .evtchn_interdomain = silo_evtchn_interdomain,
+    .grant_mapref = silo_grant_mapref,
+    .grant_transfer = silo_grant_transfer,
+    .grant_copy = silo_grant_copy,
+};
+
+void __init silo_init(void)
+{
+    printk("Initialising XSM SILO mode\n");
+
+    if ( register_xsm(&silo_xsm_ops) )
+        panic("SILO: Unable to register with XSM\n");
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/xsm/xsm_core.c b/xen/xsm/xsm_core.c
index e78f7d8ca2..91ef8a70b7 100644
--- a/xen/xsm/xsm_core.c
+++ b/xen/xsm/xsm_core.c
@@ -30,11 +30,14 @@ struct xsm_operations *xsm_ops;
 enum xsm_bootparam {
     XSM_BOOTPARAM_DUMMY,
     XSM_BOOTPARAM_FLASK,
+    XSM_BOOTPARAM_SILO,
 };
 
 static enum xsm_bootparam __initdata xsm_bootparam =
 #ifdef CONFIG_XSM_FLASK_DEFAULT
     XSM_BOOTPARAM_FLASK;
+#elif CONFIG_XSM_SILO_DEFAULT
+    XSM_BOOTPARAM_SILO;
 #else
     XSM_BOOTPARAM_DUMMY;
 #endif
@@ -48,6 +51,10 @@ static int __init parse_xsm_param(const char *s)
 #ifdef CONFIG_XSM_FLASK
     else if ( !strcmp(s, "flask") )
         xsm_bootparam = XSM_BOOTPARAM_FLASK;
+#endif
+#ifdef CONFIG_XSM_SILO
+    else if ( !strcmp(s, "silo") )
+        xsm_bootparam = XSM_BOOTPARAM_SILO;
 #endif
     else
         rc = -EINVAL;
@@ -92,6 +99,10 @@ static int __init xsm_core_init(const void *policy_buffer, size_t policy_size)
         flask_init(policy_buffer, policy_size);
         break;
 
+    case XSM_BOOTPARAM_SILO:
+        silo_init();
+        break;
+
     default:
         ASSERT_UNREACHABLE();
         break;
-- 
2.17.1
xsa295/4.9-15.patch (application/octet-stream, 3.5 KB)
From f94f961fdc89e36ef68e71e2c05203e0a4abd402 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:25 +0100
Subject: [PATCH v2 4.9 15/20] xen/arm: Turn on SILO mode by default on Arm

On Arm, exclusive load-store atomics should only be used between trusted
thread. As not all the guests are trusted, it may be possible to DoS Xen
when updating shared memory with guest atomically.

Recent patches introduced new helpers to update shared memory with guest
atomically. Those helpers relies on a memory region to be be shared with
Xen and a single guest.

At the moment, nothing prevent a guest sharing a page with Xen and as
well with another guest (e.g via grant table).

For the scope of the XSA, the quickest way is to deny communications
between unprivileged guest. So this patch is enabling and using SILO
mode by default on Arm.

Users wanted finer graine policy could wrote their own Flask policy.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Acked-by: Jan Beulich <[email protected]>
---
 xen/arch/arm/setup.c  | 8 ++++++--
 xen/common/Kconfig    | 3 ++-
 xen/include/xsm/xsm.h | 5 +++++
 xen/xsm/xsm_core.c    | 2 +-
 4 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index d23c9e82c5..6207d88b65 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -37,6 +37,7 @@
 #include <xen/vmap.h>
 #include <xen/libfdt/libfdt.h>
 #include <xen/acpi.h>
+#include <xen/warning.h>
 #include <asm/alternative.h>
 #include <asm/page.h>
 #include <asm/current.h>
@@ -798,8 +799,11 @@ void __init start_xen(unsigned long boot_phys_offset,
 
     tasklet_subsys_init();
 
-
-    xsm_dt_init();
+    if ( xsm_dt_init() != 1 )
+        warning_add("WARNING: SILO mode is not enabled.\n"
+                    "It has implications on the security of the system,\n"
+                    "unless the communications have been forbidden between\n"
+                    "untrusted domains.\n");
 
     init_maintenance_interrupt();
     init_timer_interrupt();
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index c129cfbdc2..4c3bbb2de4 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -87,7 +87,7 @@ config XENOPROF
 
 config XSM
 	bool "Xen Security Modules support"
-	default n
+	default ARM
 	---help---
 	  Enables the security framework known as Xen Security Modules which
 	  allows administrators fine-grained control over a Xen domain and
@@ -152,6 +152,7 @@ config XSM_SILO
 choice
 	prompt "Default XSM implementation"
 	depends on XSM
+	default XSM_SILO_DEFAULT if XSM_SILO && ARM
 	default XSM_FLASK_DEFAULT if XSM_FLASK
 	default XSM_SILO_DEFAULT if XSM_SILO
 	default XSM_DUMMY_DEFAULT
diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h
index ef6ff3a786..1281302471 100644
--- a/xen/include/xsm/xsm.h
+++ b/xen/include/xsm/xsm.h
@@ -719,6 +719,11 @@ extern int xsm_multiboot_policy_init(unsigned long *module_map,
 #endif
 
 #ifdef CONFIG_HAS_DEVICE_TREE
+/*
+ * Initialize XSM
+ *
+ * On success, return 1 if using SILO mode else 0.
+ */
 extern int xsm_dt_init(void);
 extern int xsm_dt_policy_init(void **policy_buffer, size_t *policy_size);
 extern bool has_xsm_magic(paddr_t);
diff --git a/xen/xsm/xsm_core.c b/xen/xsm/xsm_core.c
index 91ef8a70b7..2a2100929d 100644
--- a/xen/xsm/xsm_core.c
+++ b/xen/xsm/xsm_core.c
@@ -164,7 +164,7 @@ int __init xsm_dt_init(void)
 
     xfree(policy_buffer);
 
-    return ret;
+    return ret ?: (xsm_bootparam == XSM_BOOTPARAM_SILO);
 }
 
 /**
-- 
2.17.1
xsa295/4.9-16.patch (application/octet-stream, 9.7 KB)
From e821618ae4a59a9adc4e3662eb607833f60d0ff1 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:26 +0100
Subject: [PATCH v2 4.9 16/20] xen/bitops: Provide helpers to safely modify
 guest memory atomically

On Arm, exclusive load-store atomics should only be used between trusted
thread. As not all the guests are trusted, it may be possible to DoS Xen
when updating shared memory with guest atomically.

This patch adds a new set of helper that will update the guest memory
safely. For x86, it is already possible to use the current helpers
safely. So just wrap them.

For Arm, we will first attempt to update the guest memory with the loop
bounded by a maximum number of iterations. If it fails, we will pause the
domain and try again.

Note that this heuristics assumes that a page can only be shared between
Xen and one domain. Not Xen and multiple domain.

The maximum number of iterations is based on how many times a simple
load-store atomic operation can be executed in 1uS. The maximum value is
per-CPU to cater big.LITTLE and calculated when the CPU is booting. The
heuristic was randomly chosen and can be modified if impact too much
good-behaving guest.

Note, while test_bit does not requires to use atomic operation, a
wrapper for test_bit was added for completeness. In this case, the
domain stays constified to avoid major rework in the caller for the
time-being.

This is part of XSA-295.

Signed-of-by: Julien Grall <[email protected]>
Acked-by: Jan Beulich <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/Makefile               |  1 +
 xen/arch/arm/guest_atomics.c        | 91 +++++++++++++++++++++++++++++
 xen/include/asm-arm/guest_atomics.h | 76 ++++++++++++++++++++++++
 xen/include/asm-x86/guest_atomics.h | 30 ++++++++++
 4 files changed, 198 insertions(+)
 create mode 100644 xen/arch/arm/guest_atomics.c
 create mode 100644 xen/include/asm-arm/guest_atomics.h
 create mode 100644 xen/include/asm-x86/guest_atomics.h

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 49e1fb2f84..39abd27e7b 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_HAS_GICV3) += gic-v3.o
 obj-$(CONFIG_HAS_ITS) += gic-v3-its.o
 obj-$(CONFIG_HAS_ITS) += gic-v3-lpi.o
 obj-y += guestcopy.o
+obj-y += guest_atomics.o
 obj-y += hvm.o
 obj-y += io.o
 obj-y += irq.o
diff --git a/xen/arch/arm/guest_atomics.c b/xen/arch/arm/guest_atomics.c
new file mode 100644
index 0000000000..1b78a062f0
--- /dev/null
+++ b/xen/arch/arm/guest_atomics.c
@@ -0,0 +1,91 @@
+/*
+ * arch/arm/guest_atomics.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <xen/cpu.h>
+
+#include <asm/guest_atomics.h>
+
+DEFINE_PER_CPU_READ_MOSTLY(unsigned int, guest_safe_atomic_max);
+
+/*
+ * Heuristic to find a safe upper-limit for load-store exclusive
+ * operations on memory shared with guest.
+ *
+ * At the moment, we calculate the number of iterations of a simple
+ * load-store atomic loop in 1uS.
+ */
+static void calibrate_safe_atomic(void)
+{
+    s_time_t deadline = NOW() + MICROSECS(1);
+    unsigned int counter = 0;
+    unsigned long mem = 0;
+
+    do
+    {
+        unsigned long res, tmp;
+
+#ifdef CONFIG_ARM_32
+        asm volatile (" ldrex   %2, %1\n"
+                      " add     %2, %2, #1\n"
+                      " strex   %0, %2, %1\n"
+                      : "=&r" (res), "+Q" (mem), "=&r" (tmp));
+#else
+        asm volatile (" ldxr    %w2, %1\n"
+                      " add     %w2, %w2, #1\n"
+                      " stxr    %w0, %w2, %1\n"
+                      : "=&r" (res), "+Q" (mem), "=&r" (tmp));
+#endif
+        counter++;
+    } while (NOW() < deadline);
+
+    this_cpu(guest_safe_atomic_max) = counter;
+
+    printk(XENLOG_DEBUG
+           "CPU%u: Guest atomics will try %u times before pausing the domain\n",
+           smp_processor_id(), counter);
+}
+
+static int cpu_guest_safe_atomic_callback(struct notifier_block *nfb,
+                                          unsigned long action,
+                                          void *hcpu)
+{
+    if ( action == CPU_STARTING )
+        calibrate_safe_atomic();
+
+    return NOTIFY_DONE;
+}
+
+static struct notifier_block cpu_guest_safe_atomic_nfb = {
+    .notifier_call = cpu_guest_safe_atomic_callback,
+};
+
+static int __init guest_safe_atomic_init(void)
+{
+    register_cpu_notifier(&cpu_guest_safe_atomic_nfb);
+
+    calibrate_safe_atomic();
+
+    return 0;
+}
+presmp_initcall(guest_safe_atomic_init);
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-arm/guest_atomics.h b/xen/include/asm-arm/guest_atomics.h
new file mode 100644
index 0000000000..4f127fda41
--- /dev/null
+++ b/xen/include/asm-arm/guest_atomics.h
@@ -0,0 +1,76 @@
+#ifndef _ARM_GUEST_ATOMICS_H
+#define _ARM_GUEST_ATOMICS_H
+
+#include <xen/bitops.h>
+#include <xen/sched.h>
+
+/*
+ * The guest atomics helpers shares the same logic. We first try to use
+ * the *_timeout version of the operation. If it didn't timeout, then we
+ * successfully updated the memory. Nothing else to do.
+ *
+ * If it did timeout, then it means we didn't manage to update the
+ * memory. This is possibly because the guest is misbehaving (i.e tight
+ * store loop) but can also happen for other reasons (i.e nested Xen).
+ * In that case pause the domain and retry the operation, this time
+ * without a timeout.
+ *
+ * Note, those helpers rely on other part of the code to prevent sharing
+ * a page between Xen and multiple domain.
+ */
+
+DECLARE_PER_CPU(unsigned int, guest_safe_atomic_max);
+
+#define guest_bitop(name)                                                   \
+static inline void guest_##name(struct domain *d, int nr, volatile void *p) \
+{                                                                           \
+    if ( name##_timeout(nr, p, this_cpu(guest_safe_atomic_max)) )           \
+        return;                                                             \
+                                                                            \
+    domain_pause_nosync(d);                                                 \
+    name(nr, p);                                                            \
+    domain_unpause(d);                                                      \
+}
+
+#define guest_testop(name)                                                  \
+static inline int guest_##name(struct domain *d, int nr, volatile void *p)  \
+{                                                                           \
+    bool succeed;                                                           \
+    int oldbit;                                                             \
+                                                                            \
+    succeed = name##_timeout(nr, p, &oldbit,                                \
+                             this_cpu(guest_safe_atomic_max));              \
+    if ( succeed )                                                          \
+        return oldbit;                                                      \
+                                                                            \
+    domain_pause_nosync(d);                                                 \
+    oldbit = name(nr, p);                                                   \
+    domain_unpause(d);                                                      \
+                                                                            \
+    return oldbit;                                                          \
+}
+
+guest_bitop(set_bit)
+guest_bitop(clear_bit)
+guest_bitop(change_bit)
+
+#undef guest_bitop
+
+/* test_bit does not use load-store atomic operations */
+#define guest_test_bit(d, nr, p) ((void)(d), test_bit(nr, p))
+
+guest_testop(test_and_set_bit)
+guest_testop(test_and_clear_bit)
+guest_testop(test_and_change_bit)
+
+#undef guest_testop
+
+#endif /* _ARM_GUEST_ATOMICS_H */
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-x86/guest_atomics.h b/xen/include/asm-x86/guest_atomics.h
new file mode 100644
index 0000000000..0c71d2d278
--- /dev/null
+++ b/xen/include/asm-x86/guest_atomics.h
@@ -0,0 +1,30 @@
+#ifndef _X86_GUEST_ATOMICS_H
+#define _X86_GUEST_ATOMICS_H
+
+#include <xen/bitops.h>
+
+/*
+ * It is safe to use the atomics helpers on x86 on memory shared with
+ * the guests.
+ */
+#define guest_set_bit(d, nr, p)     ((void)(d), set_bit(nr, p))
+#define guest_clear_bit(d, nr, p)   ((void)(d), clear_bit(nr, p))
+#define guest_change_bit(d, nr, p)  ((void)(d), change_bit(nr, p))
+#define guest_test_bit(d, nr, p)    ((void)(d), test_bit(nr, p))
+
+#define guest_test_and_set_bit(d, nr, p)    \
+    ((void)(d), test_and_set_bit(nr, p))
+#define guest_test_and_clear_bit(d, nr, p)  \
+    ((void)(d), test_and_clear_bit(nr, p))
+#define guest_test_and_change_bit(d, nr, p) \
+    ((void)(d), test_and_change_bit(nr, p))
+
+#endif /* _X86_GUEST_ATOMICS_H */
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.17.1
xsa295/4.9-17.patch (application/octet-stream, 3.4 KB)
From 2f52e83b5db6b2bf68db27eb7b11f31392f0d336 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:27 +0100
Subject: [PATCH v2 4.9 17/20] xen/cmpxchg: Provide helper to safely modify
 guest memory atomically

On Arm, exclusive load-store atomics should only be used between trusted
thread. As not all the guests are trusted, it may be possible to DoS Xen
when updating shared memory with guest atomically.

This patch adds a new helper that will update the guest memory safely.
For x86, it is already possible to use the current helper safely. So
just wrap it.

For Arm, we will first attempt to update the guest memory with the
loop bounded by a maximum number of iterations. If it fails, we will
pause the domain and try again.

Note that this heuristics assumes that a page can only
be shared between Xen and one domain. Not Xen and multiple domain.

The maximum number of iterations is based on how many times atomic_inc()
can be executed in 1uS. The maximum value is per-CPU to cater big.LITTLE
and calculated when the CPU is booting.

The maximum number of iterations is based on how many times a simple
load-store atomic operation can be executed in 1uS. The maximum
value is per-CPU to cater big.LITTLE and calculated when the CPU is
booting. The heuristic was randomly chosen and can be modified if
impact too much good-behaving guest.

This is part of XSA-295.

Signed-of-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Acked-by: Jan Beulich <[email protected]>
---
 xen/include/asm-arm/guest_atomics.h | 25 +++++++++++++++++++++++++
 xen/include/asm-x86/guest_atomics.h |  2 ++
 2 files changed, 27 insertions(+)

diff --git a/xen/include/asm-arm/guest_atomics.h b/xen/include/asm-arm/guest_atomics.h
index 4f127fda41..61925d313d 100644
--- a/xen/include/asm-arm/guest_atomics.h
+++ b/xen/include/asm-arm/guest_atomics.h
@@ -65,6 +65,31 @@ guest_testop(test_and_change_bit)
 
 #undef guest_testop
 
+static inline unsigned long __guest_cmpxchg(struct domain *d,
+                                            volatile void *ptr,
+                                            unsigned long old,
+                                            unsigned long new,
+                                            unsigned int size)
+{
+    unsigned long oldval = old;
+
+    if ( __cmpxchg_mb_timeout(ptr, &oldval, new, size,
+                              this_cpu(guest_safe_atomic_max)) )
+        return oldval;
+
+    domain_pause_nosync(d);
+    oldval = __cmpxchg_mb(ptr, old, new, size);
+    domain_unpause(d);
+
+    return oldval;
+}
+
+#define guest_cmpxchg(d, ptr, o, n)                         \
+    ((__typeof__(*(ptr)))__guest_cmpxchg(d, ptr,            \
+                                         (unsigned long)(o),\
+                                         (unsigned long)(n),\
+                                         sizeof (*(ptr))))
+
 #endif /* _ARM_GUEST_ATOMICS_H */
 /*
  * Local variables:
diff --git a/xen/include/asm-x86/guest_atomics.h b/xen/include/asm-x86/guest_atomics.h
index 0c71d2d278..029417c8ff 100644
--- a/xen/include/asm-x86/guest_atomics.h
+++ b/xen/include/asm-x86/guest_atomics.h
@@ -19,6 +19,8 @@
 #define guest_test_and_change_bit(d, nr, p) \
     ((void)(d), test_and_change_bit(nr, p))
 
+#define guest_cmpxchg(d, ptr, o, n) ((void)(d), cmpxchg(ptr, o, n))
+
 #endif /* _X86_GUEST_ATOMICS_H */
 /*
  * Local variables:
-- 
2.17.1
xsa295/4.9-18.patch (application/octet-stream, 22.5 KB)
From 26de49b26f4f6d5227f31f9c77ee931a757d62c2 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:28 +0100
Subject: [PATCH v2 4.9 18/20] xen: Use guest atomics helpers when modifying
 atomically guest memory

On Arm, exclusive load-store atomics should only be used between trusted
thread. As not all the guests are trusted, it may be possible to DoS Xen
when updating shared memory with guest atomically.

This patch replaces all the atomics operations on shared memory with
a guest by the new guest atomics helpers. The x86 code was not audited
to know where guest atomics helpers could be used. I will leave that
to the x86 folks.

Note that some rework was required in order to plumb use the new guest
atomics in event channel and grant-table.

Because guest_test_bit is ignoring the parameter "d" for now, it
means there a lot of places do not need to drop the const. We may want
to revisit this in the future if the parameter "d" becomes necessary.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/domain.c             |  3 +-
 xen/arch/arm/mm.c                 |  6 ++-
 xen/common/event_2l.c             | 26 +++++++------
 xen/common/event_fifo.c           | 44 +++++++++++-----------
 xen/common/grant_table.c          | 61 +++++++++++++++++--------------
 xen/include/asm-arm/grant_table.h |  2 +-
 xen/include/asm-x86/grant_table.h |  3 +-
 7 files changed, 80 insertions(+), 65 deletions(-)

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 65f387c584..2ab315ea6f 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -23,6 +23,7 @@
 #include <asm/current.h>
 #include <asm/event.h>
 #include <asm/guest_access.h>
+#include <asm/guest_atomics.h>
 #include <asm/regs.h>
 #include <asm/p2m.h>
 #include <asm/irq.h>
@@ -940,7 +941,7 @@ void arch_dump_vcpu_info(struct vcpu *v)
 
 void vcpu_mark_events_pending(struct vcpu *v)
 {
-    int already_pending = test_and_set_bit(
+    bool already_pending = guest_test_and_set_bit(v->domain,
         0, (unsigned long *)&vcpu_info(v, evtchn_upcall_pending));
 
     if ( already_pending )
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index e22f0a0616..bb20373be6 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -40,6 +40,8 @@
 #include <xen/pfn.h>
 #include <xen/sizes.h>
 #include <xen/libfdt/libfdt.h>
+
+#include <asm/guest_atomics.h>
 #include <asm/setup.h>
 
 struct domain *dom_xen, *dom_io, *dom_cow;
@@ -1365,7 +1367,7 @@ void put_page_type(struct page_info *page)
     return;
 }
 
-void gnttab_clear_flag(unsigned long nr, uint16_t *addr)
+void gnttab_clear_flag(struct domain *d, unsigned long nr, uint16_t *addr)
 {
     /*
      * Note that this cannot be clear_bit(), as the access must be
@@ -1375,7 +1377,7 @@ void gnttab_clear_flag(unsigned long nr, uint16_t *addr)
 
     do {
         old = *addr;
-    } while (cmpxchg(addr, old, old & mask) != old);
+    } while (guest_cmpxchg(d, addr, old, old & mask) != old);
 }
 
 void gnttab_mark_dirty(struct domain *d, unsigned long l)
diff --git a/xen/common/event_2l.c b/xen/common/event_2l.c
index c730cae185..ba9185bad1 100644
--- a/xen/common/event_2l.c
+++ b/xen/common/event_2l.c
@@ -13,6 +13,8 @@
 #include <xen/sched.h>
 #include <xen/event.h>
 
+#include <asm/guest_atomics.h>
+
 static void evtchn_2l_set_pending(struct vcpu *v, struct evtchn *evtchn)
 {
     struct domain *d = v->domain;
@@ -25,12 +27,12 @@ static void evtchn_2l_set_pending(struct vcpu *v, struct evtchn *evtchn)
      * others may require explicit memory barriers.
      */
 
-    if ( test_and_set_bit(port, &shared_info(d, evtchn_pending)) )
+    if ( guest_test_and_set_bit(d, port, &shared_info(d, evtchn_pending)) )
         return;
 
-    if ( !test_bit        (port, &shared_info(d, evtchn_mask)) &&
-         !test_and_set_bit(port / BITS_PER_EVTCHN_WORD(d),
-                           &vcpu_info(v, evtchn_pending_sel)) )
+    if ( !guest_test_bit(d, port, &shared_info(d, evtchn_mask)) &&
+         !guest_test_and_set_bit(d, port / BITS_PER_EVTCHN_WORD(d),
+                                 &vcpu_info(v, evtchn_pending_sel)) )
     {
         vcpu_mark_events_pending(v);
     }
@@ -40,7 +42,7 @@ static void evtchn_2l_set_pending(struct vcpu *v, struct evtchn *evtchn)
 
 static void evtchn_2l_clear_pending(struct domain *d, struct evtchn *evtchn)
 {
-    clear_bit(evtchn->port, &shared_info(d, evtchn_pending));
+    guest_clear_bit(d, evtchn->port, &shared_info(d, evtchn_pending));
 }
 
 static void evtchn_2l_unmask(struct domain *d, struct evtchn *evtchn)
@@ -52,10 +54,10 @@ static void evtchn_2l_unmask(struct domain *d, struct evtchn *evtchn)
      * These operations must happen in strict order. Based on
      * evtchn_2l_set_pending() above.
      */
-    if ( test_and_clear_bit(port, &shared_info(d, evtchn_mask)) &&
-         test_bit          (port, &shared_info(d, evtchn_pending)) &&
-         !test_and_set_bit (port / BITS_PER_EVTCHN_WORD(d),
-                            &vcpu_info(v, evtchn_pending_sel)) )
+    if ( guest_test_and_clear_bit(d, port, &shared_info(d, evtchn_mask)) &&
+         guest_test_bit(d, port, &shared_info(d, evtchn_pending)) &&
+         !guest_test_and_set_bit(d, port / BITS_PER_EVTCHN_WORD(d),
+                                 &vcpu_info(v, evtchn_pending_sel)) )
     {
         vcpu_mark_events_pending(v);
     }
@@ -66,7 +68,8 @@ static bool_t evtchn_2l_is_pending(struct domain *d, evtchn_port_t port)
     unsigned int max_ports = BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d);
 
     ASSERT(port < max_ports);
-    return port < max_ports && test_bit(port, &shared_info(d, evtchn_pending));
+    return (port < max_ports &&
+            guest_test_bit(d, port, &shared_info(d, evtchn_pending)));
 }
 
 static bool_t evtchn_2l_is_masked(struct domain *d, evtchn_port_t port)
@@ -74,7 +77,8 @@ static bool_t evtchn_2l_is_masked(struct domain *d, evtchn_port_t port)
     unsigned int max_ports = BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d);
 
     ASSERT(port < max_ports);
-    return port >= max_ports || test_bit(port, &shared_info(d, evtchn_mask));
+    return (port >= max_ports ||
+            guest_test_bit(d, port, &shared_info(d, evtchn_mask)));
 }
 
 static void evtchn_2l_print_state(struct domain *d,
diff --git a/xen/common/event_fifo.c b/xen/common/event_fifo.c
index d5207ccedc..146314608d 100644
--- a/xen/common/event_fifo.c
+++ b/xen/common/event_fifo.c
@@ -17,6 +17,8 @@
 #include <xen/mm.h>
 #include <xen/domain_page.h>
 
+#include <asm/guest_atomics.h>
+
 #include <public/event_channel.h>
 
 static inline event_word_t *evtchn_fifo_word_from_port(struct domain *d,
@@ -50,7 +52,7 @@ static void evtchn_fifo_init(struct domain *d, struct evtchn *evtchn)
      * on the wrong VCPU or with an unexpected priority.
      */
     word = evtchn_fifo_word_from_port(d, evtchn->port);
-    if ( word && test_bit(EVTCHN_FIFO_LINKED, word) )
+    if ( word && guest_test_bit(d, EVTCHN_FIFO_LINKED, word) )
         gdprintk(XENLOG_WARNING, "domain %d, port %d already on a queue\n",
                  d->domain_id, evtchn->port);
 }
@@ -115,7 +117,7 @@ static int try_set_link(event_word_t *word, event_word_t *w, uint32_t link)
  * We block unmasking by the guest by marking the tail word as BUSY,
  * therefore, the cmpxchg() may fail at most 4 times.
  */
-static bool_t evtchn_fifo_set_link(const struct domain *d, event_word_t *word,
+static bool_t evtchn_fifo_set_link(struct domain *d, event_word_t *word,
                                    uint32_t link)
 {
     event_word_t w;
@@ -129,7 +131,7 @@ static bool_t evtchn_fifo_set_link(const struct domain *d, event_word_t *word,
         return ret;
 
     /* Lock the word to prevent guest unmasking. */
-    set_bit(EVTCHN_FIFO_BUSY, word);
+    guest_set_bit(d, EVTCHN_FIFO_BUSY, word);
 
     w = read_atomic(word);
 
@@ -139,13 +141,13 @@ static bool_t evtchn_fifo_set_link(const struct domain *d, event_word_t *word,
         if ( ret >= 0 )
         {
             if ( ret == 0 )
-                clear_bit(EVTCHN_FIFO_BUSY, word);
+                guest_clear_bit(d, EVTCHN_FIFO_BUSY, word);
             return ret;
         }
     }
     gdprintk(XENLOG_WARNING, "domain %d, port %d not linked\n",
              d->domain_id, link);
-    clear_bit(EVTCHN_FIFO_BUSY, word);
+    guest_clear_bit(d, EVTCHN_FIFO_BUSY, word);
     return 1;
 }
 
@@ -170,13 +172,13 @@ static void evtchn_fifo_set_pending(struct vcpu *v, struct evtchn *evtchn)
         return;
     }
 
-    was_pending = test_and_set_bit(EVTCHN_FIFO_PENDING, word);
+    was_pending = guest_test_and_set_bit(d, EVTCHN_FIFO_PENDING, word);
 
     /*
      * Link the event if it unmasked and not already linked.
      */
-    if ( !test_bit(EVTCHN_FIFO_MASKED, word)
-         && !test_bit(EVTCHN_FIFO_LINKED, word) )
+    if ( !guest_test_bit(d, EVTCHN_FIFO_MASKED, word) &&
+         !guest_test_bit(d, EVTCHN_FIFO_LINKED, word) )
     {
         struct evtchn_fifo_queue *q, *old_q;
         event_word_t *tail_word;
@@ -205,7 +207,7 @@ static void evtchn_fifo_set_pending(struct vcpu *v, struct evtchn *evtchn)
         if ( !old_q )
             goto done;
 
-        if ( test_and_set_bit(EVTCHN_FIFO_LINKED, word) )
+        if ( guest_test_and_set_bit(d, EVTCHN_FIFO_LINKED, word) )
         {
             spin_unlock_irqrestore(&old_q->lock, flags);
             goto done;
@@ -251,8 +253,8 @@ static void evtchn_fifo_set_pending(struct vcpu *v, struct evtchn *evtchn)
         spin_unlock_irqrestore(&q->lock, flags);
 
         if ( !linked
-             && !test_and_set_bit(q->priority,
-                                  &v->evtchn_fifo->control_block->ready) )
+             && !guest_test_and_set_bit(d, q->priority,
+                                        &v->evtchn_fifo->control_block->ready) )
             vcpu_mark_events_pending(v);
     }
  done:
@@ -274,7 +276,7 @@ static void evtchn_fifo_clear_pending(struct domain *d, struct evtchn *evtchn)
      * No need to unlink as the guest will unlink and ignore
      * non-pending events.
      */
-    clear_bit(EVTCHN_FIFO_PENDING, word);
+    guest_clear_bit(d, EVTCHN_FIFO_PENDING, word);
 }
 
 static void evtchn_fifo_unmask(struct domain *d, struct evtchn *evtchn)
@@ -286,10 +288,10 @@ static void evtchn_fifo_unmask(struct domain *d, struct evtchn *evtchn)
     if ( unlikely(!word) )
         return;
 
-    clear_bit(EVTCHN_FIFO_MASKED, word);
+    guest_clear_bit(d, EVTCHN_FIFO_MASKED, word);
 
     /* Relink if pending. */
-    if ( test_bit(EVTCHN_FIFO_PENDING, word) )
+    if ( guest_test_bit(d, EVTCHN_FIFO_PENDING, word) )
         evtchn_fifo_set_pending(v, evtchn);
 }
 
@@ -301,7 +303,7 @@ static bool_t evtchn_fifo_is_pending(struct domain *d, evtchn_port_t port)
     if ( unlikely(!word) )
         return 0;
 
-    return test_bit(EVTCHN_FIFO_PENDING, word);
+    return word && guest_test_bit(d, EVTCHN_FIFO_PENDING, word);
 }
 
 static bool_t evtchn_fifo_is_masked(struct domain *d, evtchn_port_t port)
@@ -312,7 +314,7 @@ static bool_t evtchn_fifo_is_masked(struct domain *d, evtchn_port_t port)
     if ( unlikely(!word) )
         return 1;
 
-    return test_bit(EVTCHN_FIFO_MASKED, word);
+    return !word || guest_test_bit(d, EVTCHN_FIFO_MASKED, word);
 }
 
 static bool_t evtchn_fifo_is_busy(struct domain *d, evtchn_port_t port)
@@ -323,7 +325,7 @@ static bool_t evtchn_fifo_is_busy(struct domain *d, evtchn_port_t port)
     if ( unlikely(!word) )
         return 0;
 
-    return test_bit(EVTCHN_FIFO_LINKED, word);
+    return word && guest_test_bit(d, EVTCHN_FIFO_LINKED, word);
 }
 
 static int evtchn_fifo_set_priority(struct domain *d, struct evtchn *evtchn,
@@ -350,11 +352,11 @@ static void evtchn_fifo_print_state(struct domain *d,
     word = evtchn_fifo_word_from_port(d, evtchn->port);
     if ( !word )
         printk("?     ");
-    else if ( test_bit(EVTCHN_FIFO_LINKED, word) )
-        printk("%c %-4u", test_bit(EVTCHN_FIFO_BUSY, word) ? 'B' : ' ',
+    else if ( guest_test_bit(d, EVTCHN_FIFO_LINKED, word) )
+        printk("%c %-4u", guest_test_bit(d, EVTCHN_FIFO_BUSY, word) ? 'B' : ' ',
                *word & EVTCHN_FIFO_LINK_MASK);
     else
-        printk("%c -   ", test_bit(EVTCHN_FIFO_BUSY, word) ? 'B' : ' ');
+        printk("%c -   ", guest_test_bit(d, EVTCHN_FIFO_BUSY, word) ? 'B' : ' ');
 }
 
 static const struct evtchn_port_ops evtchn_port_ops_fifo =
@@ -506,7 +508,7 @@ static void setup_ports(struct domain *d)
 
         evtchn = evtchn_from_port(d, port);
 
-        if ( test_bit(port, &shared_info(d, evtchn_pending)) )
+        if ( guest_test_bit(d, port, &shared_info(d, evtchn_pending)) )
             evtchn->pending = 1;
 
         evtchn_fifo_set_priority(d, evtchn, EVTCHN_FIFO_PRIORITY_DEFAULT);
diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index 670ae8e3aa..1e72397ee4 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -39,6 +39,7 @@
 #include <xen/vmap.h>
 #include <xsm/xsm.h>
 #include <asm/flushtlb.h>
+#include <asm/guest_atomics.h>
 
 /* 
  * This option is deprecated, use gnttab_max_frames and
@@ -546,6 +547,7 @@ static unsigned int nr_grant_entries(struct grant_table *gt)
 }
 
 static int _set_status_v1(const grant_entry_header_t *shah,
+                          struct domain *rd,
                           struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
@@ -601,8 +603,8 @@ static int _set_status_v1(const grant_entry_header_t *shah,
                          "Attempt to write-pin a r/o grant entry.\n");
         }
 
-        prev_scombo.word = cmpxchg((u32 *)shah,
-                                   scombo.word, new_scombo.word);
+        prev_scombo.word = guest_cmpxchg(rd, (u32 *)shah,
+                                         scombo.word, new_scombo.word);
         if ( likely(prev_scombo.word == scombo.word) )
             break;
 
@@ -619,6 +621,7 @@ done:
 
 static int _set_status_v2(const grant_entry_header_t *shah,
                           grant_status_t *status,
+                          struct domain *rd,
                           struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
@@ -681,8 +684,8 @@ static int _set_status_v2(const grant_entry_header_t *shah,
              (id != ldomid) ||
              (!readonly && (flags & GTF_readonly)) )
         {
-            gnttab_clear_flag(_GTF_writing, status);
-            gnttab_clear_flag(_GTF_reading, status);
+            gnttab_clear_flag(rd, _GTF_writing, status);
+            gnttab_clear_flag(rd, _GTF_reading, status);
             PIN_FAIL(done, GNTST_general_error,
                      "Unstable flags (%x) or dom (%d). (expected dom %d) "
                      "(r/w: %d)\n",
@@ -693,7 +696,7 @@ static int _set_status_v2(const grant_entry_header_t *shah,
     {
         if ( unlikely(flags & GTF_readonly) )
         {
-            gnttab_clear_flag(_GTF_writing, status);
+            gnttab_clear_flag(rd, _GTF_writing, status);
             PIN_FAIL(done, GNTST_general_error,
                      "Unstable grant readonly flag\n");
         }
@@ -706,6 +709,7 @@ done:
 
 static int _set_status(const grant_entry_header_t *shah,
                        grant_status_t *status,
+                       struct domain *rd,
                        unsigned rgt_version,
                        struct active_grant_entry *act,
                        int readonly,
@@ -714,9 +718,9 @@ static int _set_status(const grant_entry_header_t *shah,
 {
 
     if ( rgt_version == 1 )
-        return _set_status_v1(shah, act, readonly, mapflag, ldomid);
+        return _set_status_v1(shah, rd, act, readonly, mapflag, ldomid);
     else
-        return _set_status_v2(shah, status, act, readonly, mapflag, ldomid);
+        return _set_status_v2(shah, status, rd, act, readonly, mapflag, ldomid);
 }
 
 static struct active_grant_entry *grant_map_exists(const struct domain *ld,
@@ -884,7 +888,7 @@ __gnttab_map_grant_ref(
          (!(op->flags & GNTMAP_readonly) &&
           !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask))) )
     {
-        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+        if ( (rc = _set_status(shah, status, rd, rgt->gt_version, act,
                                op->flags & GNTMAP_readonly, 1,
                                ld->domain_id) != GNTST_okay) )
             goto act_release_out;
@@ -1097,10 +1101,10 @@ __gnttab_map_grant_ref(
  unlock_out_clear:
     if ( !(op->flags & GNTMAP_readonly) &&
          !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) )
-        gnttab_clear_flag(_GTF_writing, status);
+        gnttab_clear_flag(rd, _GTF_writing, status);
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 
  act_release_out:
     active_entry_release(act);
@@ -1382,10 +1386,10 @@ __gnttab_unmap_common_complete(struct gnttab_unmap_common *op)
 
     if ( ((act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0) &&
          !(op->done & GNTMAP_readonly) )
-        gnttab_clear_flag(_GTF_writing, status);
+        gnttab_clear_flag(rd, _GTF_writing, status);
 
     if ( act->pin == 0 )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 
     active_entry_release(act);
     grant_read_unlock(rgt);
@@ -1869,8 +1873,8 @@ gnttab_prepare_for_transfer(
         new_scombo = scombo;
         new_scombo.shorts.flags |= GTF_transfer_committed;
 
-        prev_scombo.word = cmpxchg((u32 *)&sha->flags,
-                                   scombo.word, new_scombo.word);
+        prev_scombo.word = guest_cmpxchg(rd, (u32 *)&sha->flags,
+                                         scombo.word, new_scombo.word);
         if ( likely(prev_scombo.word == scombo.word) )
             break;
 
@@ -2165,11 +2169,11 @@ __release_grant_for_copy(
 
         act->pin -= GNTPIN_hstw_inc;
         if ( !(act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) )
-            gnttab_clear_flag(_GTF_writing, status);
+            gnttab_clear_flag(rd, _GTF_writing, status);
     }
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 
     active_entry_release(act);
     grant_read_unlock(rgt);
@@ -2191,14 +2195,15 @@ __release_grant_for_copy(
    under the domain's grant table lock. */
 /* Only safe on transitive grants.  Even then, note that we don't
    attempt to drop any pin on the referent grant. */
-static void __fixup_status_for_copy_pin(const struct active_grant_entry *act,
-                                   uint16_t *status)
+static void __fixup_status_for_copy_pin(struct domain *rd,
+                                        const struct active_grant_entry *act,
+                                        uint16_t *status)
 {
     if ( !(act->pin & (GNTPIN_hstw_mask | GNTPIN_devw_mask)) )
-        gnttab_clear_flag(_GTF_writing, status);
+        gnttab_clear_flag(rd, _GTF_writing, status);
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 }
 
 /* Grab a frame number from a grant entry and update the flags and pin
@@ -2258,7 +2263,7 @@ __acquire_grant_for_copy(
     {
         if ( (!old_pin || (!readonly &&
                            !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)))) &&
-             (rc = _set_status_v2(shah, status, act, readonly, 0,
+             (rc = _set_status_v2(shah, status, rd, act, readonly, 0,
                                   ldom)) != GNTST_okay )
             goto unlock_out;
 
@@ -2306,7 +2311,7 @@ __acquire_grant_for_copy(
 
         if ( rc != GNTST_okay )
         {
-            __fixup_status_for_copy_pin(act, status);
+            __fixup_status_for_copy_pin(rd, act, status);
             rcu_unlock_domain(td);
             active_entry_release(act);
             grant_read_unlock(rgt);
@@ -2328,7 +2333,7 @@ __acquire_grant_for_copy(
                           !act->is_sub_page)) )
         {
             __release_grant_for_copy(td, trans_gref, readonly);
-            __fixup_status_for_copy_pin(act, status);
+            __fixup_status_for_copy_pin(rd, act, status);
             rcu_unlock_domain(td);
             active_entry_release(act);
             grant_read_unlock(rgt);
@@ -2357,7 +2362,7 @@ __acquire_grant_for_copy(
     else if ( !old_pin ||
               (!readonly && !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask))) )
     {
-        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+        if ( (rc = _set_status(shah, status, rd, rgt->gt_version, act,
                                readonly, 0, ldom)) != GNTST_okay )
              goto unlock_out;
 
@@ -2443,10 +2448,10 @@ __acquire_grant_for_copy(
  unlock_out_clear:
     if ( !(readonly) &&
          !(act->pin & (GNTPIN_hstw_mask | GNTPIN_devw_mask)) )
-        gnttab_clear_flag(_GTF_writing, status);
+        gnttab_clear_flag(rd, _GTF_writing, status);
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 
  unlock_out:
     active_entry_release(act);
@@ -3548,11 +3553,11 @@ gnttab_release_mappings(
             }
 
             if ( (act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0 )
-                gnttab_clear_flag(_GTF_writing, status);
+                gnttab_clear_flag(rd, _GTF_writing, status);
         }
 
         if ( act->pin == 0 )
-            gnttab_clear_flag(_GTF_reading, status);
+            gnttab_clear_flag(rd, _GTF_reading, status);
 
         active_entry_release(act);
         grant_read_unlock(rgt);
diff --git a/xen/include/asm-arm/grant_table.h b/xen/include/asm-arm/grant_table.h
index b47220c1c6..886f8398c3 100644
--- a/xen/include/asm-arm/grant_table.h
+++ b/xen/include/asm-arm/grant_table.h
@@ -6,7 +6,7 @@
 #define INITIAL_NR_GRANT_FRAMES 4
 #define GNTTAB_MAX_VERSION 1
 
-void gnttab_clear_flag(unsigned long nr, uint16_t *addr);
+void gnttab_clear_flag(struct domain *d, unsigned long nr, uint16_t *addr);
 int create_grant_host_mapping(unsigned long gpaddr,
         unsigned long mfn, unsigned int flags, unsigned int
         cache_flags);
diff --git a/xen/include/asm-x86/grant_table.h b/xen/include/asm-x86/grant_table.h
index 95101bfc7e..5e46c5aef6 100644
--- a/xen/include/asm-x86/grant_table.h
+++ b/xen/include/asm-x86/grant_table.h
@@ -56,7 +56,8 @@ int replace_grant_host_mapping(
 
 #define gnttab_mark_dirty(d, f) paging_mark_dirty((d), _mfn(f))
 
-static inline void gnttab_clear_flag(unsigned int nr, uint16_t *st)
+static inline void gnttab_clear_flag(struct domain *d, unsigned int nr,
+                                     uint16_t *st)
 {
     /*
      * Note that this cannot be clear_bit(), as the access must be
-- 
2.17.1
xsa295/4.9-19.patch (application/octet-stream, 4.1 KB)
From 76f81e740c860a1ced72a34d8080b9443910d697 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:29 +0100
Subject: [PATCH v2 4.9 19/20] xen/arm: Add performance counters in guest
 atomic helpers

Add performance counters in guest atomic helpers to be able to detect
whether a guest is often paused during the operations.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Acked-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/guest_atomics.h | 12 ++++++++++++
 xen/include/asm-arm/perfc_defn.h    |  3 +++
 2 files changed, 15 insertions(+)

diff --git a/xen/include/asm-arm/guest_atomics.h b/xen/include/asm-arm/guest_atomics.h
index 61925d313d..698508bf87 100644
--- a/xen/include/asm-arm/guest_atomics.h
+++ b/xen/include/asm-arm/guest_atomics.h
@@ -24,9 +24,13 @@ DECLARE_PER_CPU(unsigned int, guest_safe_atomic_max);
 #define guest_bitop(name)                                                   \
 static inline void guest_##name(struct domain *d, int nr, volatile void *p) \
 {                                                                           \
+    perfc_incr(atomics_guest);                                              \
+                                                                            \
     if ( name##_timeout(nr, p, this_cpu(guest_safe_atomic_max)) )           \
         return;                                                             \
                                                                             \
+    perfc_incr(atomics_guest_paused);                                       \
+                                                                            \
     domain_pause_nosync(d);                                                 \
     name(nr, p);                                                            \
     domain_unpause(d);                                                      \
@@ -38,11 +42,15 @@ static inline int guest_##name(struct domain *d, int nr, volatile void *p)  \
     bool succeed;                                                           \
     int oldbit;                                                             \
                                                                             \
+    perfc_incr(atomics_guest);                                              \
+                                                                            \
     succeed = name##_timeout(nr, p, &oldbit,                                \
                              this_cpu(guest_safe_atomic_max));              \
     if ( succeed )                                                          \
         return oldbit;                                                      \
                                                                             \
+    perfc_incr(atomics_guest_paused);                                       \
+                                                                            \
     domain_pause_nosync(d);                                                 \
     oldbit = name(nr, p);                                                   \
     domain_unpause(d);                                                      \
@@ -73,10 +81,14 @@ static inline unsigned long __guest_cmpxchg(struct domain *d,
 {
     unsigned long oldval = old;
 
+    perfc_incr(atomics_guest);
+
     if ( __cmpxchg_mb_timeout(ptr, &oldval, new, size,
                               this_cpu(guest_safe_atomic_max)) )
         return oldval;
 
+    perfc_incr(atomics_guest_paused);
+
     domain_pause_nosync(d);
     oldval = __cmpxchg_mb(ptr, old, new, size);
     domain_unpause(d);
diff --git a/xen/include/asm-arm/perfc_defn.h b/xen/include/asm-arm/perfc_defn.h
index 5f957ee6ec..2599734cdc 100644
--- a/xen/include/asm-arm/perfc_defn.h
+++ b/xen/include/asm-arm/perfc_defn.h
@@ -73,6 +73,9 @@ PERFCOUNTER(phys_timer_irqs,  "Physical timer interrupts")
 PERFCOUNTER(virt_timer_irqs,  "Virtual timer interrupts")
 PERFCOUNTER(maintenance_irqs, "Maintenance interrupts")
 
+PERFCOUNTER(atomics_guest,    "atomics: guest access")
+PERFCOUNTER(atomics_guest_paused,   "atomics: guest paused")
+
 /*#endif*/ /* __XEN_PERFC_DEFN_H__ */
 
 /*
-- 
2.17.1
xsa295/4.9-20.patch (application/octet-stream, 6.4 KB)
From 4b7b96d60a76444e1c5325c0ed7bd7519d3fd5ad Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:30 +0100
Subject: [PATCH v2 4.9 20/20] xen/arm: grant-table: Protect gnttab_clear_flag
 against guest misbehavior

The function gnttab_clear_flag is used to clear the access flags. On
Arm, it is implemented using a loop and guest_cmpxchg.

It is possible that guest_cmpxchg will always return a different value
than old. This can happen if the guest updated the memory before Xen has
time to do the exchange. Because of that, there are no way for to
promise the loop will end.

It is possible to make the current code safe by re-using the same
principle as applied on the guest atomic helper. However this patch
takes a different approach that should lead to more efficient code in
the default case.

A new helper is introduced to clear a set of bits on a 16-bits word.
This should avoid a an extra loop to check cmpxchg succeeded.

Note that a mask is used instead of a bit, so the helper can be re-used
later on for clearing multiple flags at the same time.

This is part of XSA-295.

Reported-by: Andrew Cooper <[email protected]>
Signed-off-by: Julien Grall <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/arm32/lib/bitops.c     | 35 +++++++++++++++++++++++++++++
 xen/arch/arm/arm64/lib/bitops.c     | 33 +++++++++++++++++++++++++++
 xen/arch/arm/mm.c                   | 10 +--------
 xen/include/asm-arm/bitops.h        |  4 ++++
 xen/include/asm-arm/guest_atomics.h | 13 +++++++++++
 5 files changed, 86 insertions(+), 9 deletions(-)

diff --git a/xen/arch/arm/arm32/lib/bitops.c b/xen/arch/arm/arm32/lib/bitops.c
index 08750314fc..3dca769bf0 100644
--- a/xen/arch/arm/arm32/lib/bitops.c
+++ b/xen/arch/arm/arm32/lib/bitops.c
@@ -126,6 +126,41 @@ testop(test_and_change_bit, eor)
 testop(test_and_clear_bit, bic)
 testop(test_and_set_bit, orr)
 
+static always_inline bool int_clear_mask16(uint16_t mask, volatile uint16_t *p,
+                                           bool timeout, unsigned int max_try)
+{
+    unsigned long res, tmp;
+
+    prefetchw((const uint16_t *)p);
+
+    do
+    {
+        asm volatile ("// int_clear_mask16\n"
+        "   ldrexh  %2, %1\n"
+        "   bic     %2, %2, %3\n"
+        "   strexh  %0, %2, %1\n"
+        : "=&r" (res), "+Qo" (*p), "=&r" (tmp)
+        : "r" (mask));
+
+        if ( !res )
+            break;
+    } while ( !timeout || ((--max_try) > 0) );
+
+    return !res;
+}
+
+void clear_mask16(uint16_t mask, volatile void *p)
+{
+    if ( !int_clear_mask16(mask, p, false, 0) )
+        ASSERT_UNREACHABLE();
+}
+
+bool clear_mask16_timeout(uint16_t mask, volatile void *p,
+                          unsigned int max_try)
+{
+    return int_clear_mask16(mask, p, true, max_try);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
index 78bf4ed8c5..27688e5418 100644
--- a/xen/arch/arm/arm64/lib/bitops.c
+++ b/xen/arch/arm/arm64/lib/bitops.c
@@ -118,6 +118,39 @@ testop(test_and_change_bit, eor)
 testop(test_and_clear_bit, bic)
 testop(test_and_set_bit, orr)
 
+static always_inline bool int_clear_mask16(uint16_t mask, volatile uint16_t *p,
+                                           bool timeout, unsigned int max_try)
+{
+    unsigned long res, tmp;
+
+    do
+    {
+        asm volatile ("//  int_clear_mask16\n"
+        "   ldxrh   %w2, %1\n"
+        "   bic     %w2, %w2, %w3\n"
+        "   stxrh   %w0, %w2, %1\n"
+        : "=&r" (res), "+Q" (*p), "=&r" (tmp)
+        : "r" (mask));
+
+        if ( !res )
+            break;
+    } while ( !timeout || ((--max_try) > 0) );
+
+    return !res;
+}
+
+void clear_mask16(uint16_t mask, volatile void *p)
+{
+    if ( !int_clear_mask16(mask, p, false, 0) )
+        ASSERT_UNREACHABLE();
+}
+
+bool clear_mask16_timeout(uint16_t mask, volatile void *p,
+                          unsigned int max_try)
+{
+    return int_clear_mask16(mask, p, true, max_try);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index bb20373be6..d927f34c0c 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -1369,15 +1369,7 @@ void put_page_type(struct page_info *page)
 
 void gnttab_clear_flag(struct domain *d, unsigned long nr, uint16_t *addr)
 {
-    /*
-     * Note that this cannot be clear_bit(), as the access must be
-     * confined to the specified 2 bytes.
-     */
-    uint16_t mask = ~(1 << nr), old;
-
-    do {
-        old = *addr;
-    } while (guest_cmpxchg(d, addr, old, old & mask) != old);
+    guest_clear_mask16(d, BIT(nr), addr);
 }
 
 void gnttab_mark_dirty(struct domain *d, unsigned long l)
diff --git a/xen/include/asm-arm/bitops.h b/xen/include/asm-arm/bitops.h
index 172bbaee7e..3b17db096f 100644
--- a/xen/include/asm-arm/bitops.h
+++ b/xen/include/asm-arm/bitops.h
@@ -52,6 +52,8 @@ int test_and_set_bit(int nr, volatile void *p);
 int test_and_clear_bit(int nr, volatile void *p);
 int test_and_change_bit(int nr, volatile void *p);
 
+void clear_mask16(uint16_t mask, volatile void *p);
+
 /*
  * The helpers below may fail to update the memory if the action takes
  * too long.
@@ -70,6 +72,8 @@ bool test_and_clear_bit_timeout(int nr, volatile void *p,
                                 int *oldbit, unsigned int max_try);
 bool test_and_change_bit_timeout(int nr, volatile void *p,
                                  int *oldbit, unsigned int max_try);
+bool clear_mask16_timeout(uint16_t mask, volatile void *p,
+                          unsigned int max_try);
 
 /**
  * __test_and_set_bit - Set a bit and return its old value
diff --git a/xen/include/asm-arm/guest_atomics.h b/xen/include/asm-arm/guest_atomics.h
index 698508bf87..af27cc627b 100644
--- a/xen/include/asm-arm/guest_atomics.h
+++ b/xen/include/asm-arm/guest_atomics.h
@@ -73,6 +73,19 @@ guest_testop(test_and_change_bit)
 
 #undef guest_testop
 
+static inline void guest_clear_mask16(struct domain *d, uint16_t mask,
+                                      volatile uint16_t *p)
+{
+    perfc_incr(atomics_guest);
+
+    if ( clear_mask16_timeout(mask, p, this_cpu(guest_safe_atomic_max)) )
+        return;
+
+    domain_pause_nosync(d);
+    clear_mask16(mask, p);
+    domain_unpause(d);
+}
+
 static inline unsigned long __guest_cmpxchg(struct domain *d,
                                             volatile void *ptr,
                                             unsigned long old,
-- 
2.17.1
xsa295/4.10-01.patch (application/octet-stream, 2.3 KB)
From 824b31047e300b0a748bbf994d29c00fcf22f2f9 Mon Sep 17 00:00:00 2001
From: Jan Beulich <[email protected]>
Date: Thu, 23 May 2019 10:42:29 -0700
Subject: [PATCH v2 4.10 01/20] events: drop arch_evtchn_inject()

Have the only user call vcpu_mark_events_pending() instead, at the same
time arranging for correct ordering of the writes (evtchn_pending_sel
should be written before evtchn_upcall_pending).

Signed-off-by: Jan Beulich <[email protected]>
Reviewed-by: Andrew Cooper <[email protected]>
Reviewed-by: Julien Grall <[email protected]>
---
 xen/arch/arm/vgic.c     | 5 -----
 xen/common/domain.c     | 3 +--
 xen/include/xen/event.h | 3 ---
 3 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 223030db30..7a78a18429 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -586,11 +586,6 @@ void vgic_vcpu_inject_spi(struct domain *d, unsigned int virq)
     vgic_vcpu_inject_irq(v, virq);
 }
 
-void arch_evtchn_inject(struct vcpu *v)
-{
-    vgic_vcpu_inject_irq(v, v->domain->arch.evtchn_irq);
-}
-
 bool vgic_emulate(struct cpu_user_regs *regs, union hsr hsr)
 {
     struct vcpu *v = current;
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 8fbd33d4c6..3fa45b8591 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -1220,10 +1220,9 @@ int map_vcpu_info(struct vcpu *v, unsigned long gfn, unsigned offset)
      * Mark everything as being pending just to make sure nothing gets
      * lost.  The domain will get a spurious event, but it can cope.
      */
-    vcpu_info(v, evtchn_upcall_pending) = 1;
     for ( i = 0; i < BITS_PER_EVTCHN_WORD(d); i++ )
         set_bit(i, &vcpu_info(v, evtchn_pending_sel));
-    arch_evtchn_inject(v);
+    vcpu_mark_events_pending(v);
 
     return 0;
 }
diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h
index ebb879e88d..b8152a9831 100644
--- a/xen/include/xen/event.h
+++ b/xen/include/xen/event.h
@@ -83,9 +83,6 @@ int guest_enabled_event(struct vcpu *v, uint32_t virq);
 /* Notify remote end of a Xen-attached event channel.*/
 void notify_via_xen_event_channel(struct domain *ld, int lport);
 
-/* Inject an event channel notification into the guest */
-void arch_evtchn_inject(struct vcpu *v);
-
 /*
  * Internal event channel object storage.
  *
-- 
2.17.1
xsa295/4.10-02.patch (application/octet-stream, 3.7 KB)
From 70ccb440fea1a4c136014a1a605228c29db7f662 Mon Sep 17 00:00:00 2001
From: Jan Beulich <[email protected]>
Date: Tue, 12 Mar 2019 14:40:56 +0100
Subject: [PATCH v2 4.10 02/20] common: avoid atomic read-modify-write accesses
 in map_vcpu_info()

There's no need to set the evtchn_pending_sel bits one by one. Simply
write full words with all ones.

For Arm this requires extending write_atomic() to also handle 64-bit
values; for symmetry read_atomic() gets adjusted as well.

Signed-off-by: Jan Beulich <[email protected]>
Reviewed-by: Andrew Cooper <[email protected]>
Reviewed-by: Julien Grall <[email protected]>
---
 xen/common/domain.c          |  9 ++++++---
 xen/include/asm-arm/atomic.h | 15 +++++++++++++++
 2 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/xen/common/domain.c b/xen/common/domain.c
index 3fa45b8591..57e8636b38 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -1167,7 +1167,6 @@ int map_vcpu_info(struct vcpu *v, unsigned long gfn, unsigned offset)
     void *mapping;
     vcpu_info_t *new_info;
     struct page_info *page;
-    int i;
 
     if ( offset > (PAGE_SIZE - sizeof(vcpu_info_t)) )
         return -EINVAL;
@@ -1220,8 +1219,12 @@ int map_vcpu_info(struct vcpu *v, unsigned long gfn, unsigned offset)
      * Mark everything as being pending just to make sure nothing gets
      * lost.  The domain will get a spurious event, but it can cope.
      */
-    for ( i = 0; i < BITS_PER_EVTCHN_WORD(d); i++ )
-        set_bit(i, &vcpu_info(v, evtchn_pending_sel));
+#ifdef CONFIG_COMPAT
+    if ( !has_32bit_shinfo(d) )
+        write_atomic(&new_info->native.evtchn_pending_sel, ~0);
+    else
+#endif
+        write_atomic(&vcpu_info(v, evtchn_pending_sel), ~0);
     vcpu_mark_events_pending(v);
 
     return 0;
diff --git a/xen/include/asm-arm/atomic.h b/xen/include/asm-arm/atomic.h
index afb3eeea5b..7b4c987fa7 100644
--- a/xen/include/asm-arm/atomic.h
+++ b/xen/include/asm-arm/atomic.h
@@ -55,6 +55,19 @@ build_atomic_write(write_int_atomic, "",  WORD, int, "r")
 #if defined (CONFIG_ARM_64)
 build_atomic_read(read_u64_atomic, "", "", uint64_t, "=r")
 build_atomic_write(write_u64_atomic, "", "", uint64_t, "r")
+#elif defined (CONFIG_ARM_32)
+static inline uint64_t read_u64_atomic(const volatile uint64_t *addr)
+{
+    uint64_t val;
+
+    asm volatile ( "ldrd %0,%H0,%1" : "=r" (val) : "m" (*addr) );
+
+    return val;
+}
+static inline void write_u64_atomic(volatile uint64_t *addr, uint64_t val)
+{
+    asm volatile ( "strd %1,%H1,%0" : "=m" (*addr) : "r" (val) );
+}
 #endif
 
 build_add_sized(add_u8_sized, "b", BYTE, uint8_t, "ri")
@@ -69,6 +82,7 @@ void __bad_atomic_size(void);
     case 1: __x = (typeof(*p))read_u8_atomic((uint8_t *)p); break;      \
     case 2: __x = (typeof(*p))read_u16_atomic((uint16_t *)p); break;    \
     case 4: __x = (typeof(*p))read_u32_atomic((uint32_t *)p); break;    \
+    case 8: __x = (typeof(*p))read_u64_atomic((uint64_t *)p); break;    \
     default: __x = 0; __bad_atomic_size(); break;                       \
     }                                                                   \
     __x;                                                                \
@@ -80,6 +94,7 @@ void __bad_atomic_size(void);
     case 1: write_u8_atomic((uint8_t *)p, (uint8_t)__x); break;         \
     case 2: write_u16_atomic((uint16_t *)p, (uint16_t)__x); break;      \
     case 4: write_u32_atomic((uint32_t *)p, (uint32_t)__x); break;      \
+    case 8: write_u64_atomic((uint64_t *)p, (uint64_t)__x); break;      \
     default: __bad_atomic_size(); break;                                \
     }                                                                   \
     __x;                                                                \
-- 
2.17.1
xsa295/4.10-03.patch (application/octet-stream, 2.1 KB)
From c2b590ccbd4d3a5c326f1d0196d82d09e599fa4b Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:16 +0100
Subject: [PATCH v2 4.10 03/20] xen/arm: Add an isb() before reading CNTPCT_EL0
 to prevent re-ordering

Per D8.2.1 in ARM DDI 0487C.a, "a read to CNTPCT_EL0 can occur
speculatively and out of order relative to other instructions executed
on the same PE."

Add an instruction barrier to get accurate number of cycles when
requested in get_cycles(). For the other users of CNPCT_EL0, replace by
a call to get_cycles().

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Acked-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/time.c        | 4 ++--
 xen/include/asm-arm/time.h | 5 ++++-
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/time.c b/xen/arch/arm/time.c
index 105c7410c7..825ef374e8 100644
--- a/xen/arch/arm/time.c
+++ b/xen/arch/arm/time.c
@@ -150,7 +150,7 @@ void __init preinit_xen_time(void)
     if ( res )
         panic("Timer: Cannot initialize platform timer");
 
-    boot_count = READ_SYSREG64(CNTPCT_EL0);
+    boot_count = get_cycles();
 }
 
 static void __init init_dt_xen_time(void)
@@ -191,7 +191,7 @@ int __init init_xen_time(void)
 /* Return number of nanoseconds since boot */
 s_time_t get_s_time(void)
 {
-    uint64_t ticks = READ_SYSREG64(CNTPCT_EL0) - boot_count;
+    uint64_t ticks = get_cycles() - boot_count;
     return ticks_to_ns(ticks);
 }
 
diff --git a/xen/include/asm-arm/time.h b/xen/include/asm-arm/time.h
index 5b9a31de91..ca30406669 100644
--- a/xen/include/asm-arm/time.h
+++ b/xen/include/asm-arm/time.h
@@ -1,6 +1,8 @@
 #ifndef __ARM_TIME_H__
 #define __ARM_TIME_H__
 
+#include <asm/system.h>
+
 #define DT_MATCH_TIMER                      \
     DT_MATCH_COMPATIBLE("arm,armv7-timer"), \
     DT_MATCH_COMPATIBLE("arm,armv8-timer")
@@ -9,7 +11,8 @@ typedef unsigned long cycles_t;
 
 static inline cycles_t get_cycles (void)
 {
-        return 0;
+        isb();
+        return READ_SYSREG64(CNTPCT_EL0);
 }
 
 /* List of timer's IRQ */
-- 
2.17.1
xsa295/4.10-04.patch (application/octet-stream, 6.6 KB)
From 9273206db1eda3e3c98abf404f371c6789c2e3c7 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:17 +0100
Subject: [PATCH v2 4.10 04/20] xen/grant_table: Rework the prototype of
 _set_status* for lisibility

It is not clear from the parameters name whether domid and gt_version
correspond to the local or remote domain. A follow-up patch will make
them more confusing.

So rename domid (resp. gt_version) to ldomid (resp. rgt_version). At
the same time re-order the parameters to hopefully make it more
readable.

This is part of XSA-295.

Suggested-by: Jan Beulich <[email protected]>
Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Jan Beulich <[email protected]>
Acked-by: Stefano Stabellini <[email protected]>
---
 xen/common/grant_table.c | 57 ++++++++++++++++++++--------------------
 1 file changed, 28 insertions(+), 29 deletions(-)

diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index 42ea50f485..0327335585 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -652,11 +652,11 @@ static unsigned int nr_grant_entries(struct grant_table *gt)
     return 0;
 }
 
-static int _set_status_v1(domid_t  domid,
+static int _set_status_v1(const grant_entry_header_t *shah,
+                          struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
-                          grant_entry_header_t *shah,
-                          struct active_grant_entry *act)
+                          domid_t  ldomid)
 {
     int rc = GNTST_okay;
     union grant_combo scombo, prev_scombo, new_scombo;
@@ -691,11 +691,11 @@ static int _set_status_v1(domid_t  domid,
         if ( !act->pin &&
              (((scombo.shorts.flags & mask) !=
                GTF_permit_access) ||
-              (scombo.shorts.domid != domid)) )
+              (scombo.shorts.domid != ldomid)) )
             PIN_FAIL(done, GNTST_general_error,
                      "Bad flags (%x) or dom (%d); expected d%d\n",
                      scombo.shorts.flags, scombo.shorts.domid,
-                     domid);
+                     ldomid);
 
         new_scombo = scombo;
         new_scombo.shorts.flags |= GTF_reading;
@@ -724,12 +724,12 @@ done:
     return rc;
 }
 
-static int _set_status_v2(domid_t  domid,
+static int _set_status_v2(const grant_entry_header_t *shah,
+                          grant_status_t *status,
+                          struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
-                          grant_entry_header_t *shah,
-                          struct active_grant_entry *act,
-                          grant_status_t *status)
+                          domid_t  ldomid)
 {
     int      rc    = GNTST_okay;
     union grant_combo scombo;
@@ -755,10 +755,10 @@ static int _set_status_v2(domid_t  domid,
     if ( !act->pin &&
          ( (((flags & mask) != GTF_permit_access) &&
             ((flags & mask) != GTF_transitive)) ||
-          (id != domid)) )
+          (id != ldomid)) )
         PIN_FAIL(done, GNTST_general_error,
                  "Bad flags (%x) or dom (%d); expected d%d, flags %x\n",
-                 flags, id, domid, mask);
+                 flags, id, ldomid, mask);
 
     if ( readonly )
     {
@@ -785,14 +785,14 @@ static int _set_status_v2(domid_t  domid,
     {
         if ( (((flags & mask) != GTF_permit_access) &&
               ((flags & mask) != GTF_transitive)) ||
-             (id != domid) ||
+             (id != ldomid) ||
              (!readonly && (flags & GTF_readonly)) )
         {
             gnttab_clear_flag(_GTF_writing, status);
             gnttab_clear_flag(_GTF_reading, status);
             PIN_FAIL(done, GNTST_general_error,
                      "Unstable flags (%x) or dom (%d); expected d%d (r/w: %d)\n",
-                     flags, id, domid, !readonly);
+                     flags, id, ldomid, !readonly);
         }
     }
     else
@@ -810,19 +810,19 @@ done:
 }
 
 
-static int _set_status(unsigned gt_version,
-                       domid_t  domid,
+static int _set_status(const grant_entry_header_t *shah,
+                       grant_status_t *status,
+                       unsigned rgt_version,
+                       struct active_grant_entry *act,
                        int readonly,
                        int mapflag,
-                       grant_entry_header_t *shah,
-                       struct active_grant_entry *act,
-                       grant_status_t *status)
+                       domid_t ldomid)
 {
 
-    if ( gt_version == 1 )
-        return _set_status_v1(domid, readonly, mapflag, shah, act);
+    if ( rgt_version == 1 )
+        return _set_status_v1(shah, act, readonly, mapflag, ldomid);
     else
-        return _set_status_v2(domid, readonly, mapflag, shah, act, status);
+        return _set_status_v2(shah, status, act, readonly, mapflag, ldomid);
 }
 
 static struct active_grant_entry *grant_map_exists(const struct domain *ld,
@@ -993,9 +993,9 @@ map_grant_ref(
          (!(op->flags & GNTMAP_readonly) &&
           !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask))) )
     {
-        if ( (rc = _set_status(rgt->gt_version, ld->domain_id,
-                               op->flags & GNTMAP_readonly,
-                               1, shah, act, status) ) != GNTST_okay )
+        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+                               op->flags & GNTMAP_readonly, 1,
+                               ld->domain_id) != GNTST_okay) )
             goto act_release_out;
 
         if ( !act->pin )
@@ -2449,8 +2449,8 @@ acquire_grant_for_copy(
     {
         if ( (!old_pin || (!readonly &&
                            !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)))) &&
-             (rc = _set_status_v2(ldom, readonly, 0, shah, act,
-                                  status)) != GNTST_okay )
+             (rc = _set_status_v2(shah, status, act, readonly, 0,
+                                  ldom)) != GNTST_okay )
             goto unlock_out;
 
         if ( !allow_transitive )
@@ -2549,9 +2549,8 @@ acquire_grant_for_copy(
     else if ( !old_pin ||
               (!readonly && !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask))) )
     {
-        if ( (rc = _set_status(rgt->gt_version, ldom,
-                               readonly, 0, shah, act,
-                               status) ) != GNTST_okay )
+        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+                               readonly, 0, ldom)) != GNTST_okay )
              goto unlock_out;
 
         td = rd;
-- 
2.17.1
xsa295/4.10-05.patch (application/octet-stream, 7.8 KB)
From 90611314aeda7ef8128b71f576750a9fa2a99b2f Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:18 +0100
Subject: [PATCH v2 4.10 05/20] xen/arm64: bitops: Rewrite bitop helpers in C

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/README.LinuxPrimitives |  1 -
 xen/arch/arm/arm64/lib/bitops.S     | 67 ---------------------
 xen/arch/arm/arm64/lib/bitops.c     | 90 +++++++++++++++++++++++++++++
 3 files changed, 90 insertions(+), 68 deletions(-)
 delete mode 100644 xen/arch/arm/arm64/lib/bitops.S
 create mode 100644 xen/arch/arm/arm64/lib/bitops.c

diff --git a/xen/arch/arm/README.LinuxPrimitives b/xen/arch/arm/README.LinuxPrimitives
index 028e8721f9..891667a5da 100644
--- a/xen/arch/arm/README.LinuxPrimitives
+++ b/xen/arch/arm/README.LinuxPrimitives
@@ -8,7 +8,6 @@ arm64:
 
 bitops: last sync @ v3.16-rc6 (last commit: 8715466b6027)
 
-linux/arch/arm64/lib/bitops.S           xen/arch/arm/arm64/lib/bitops.S
 linux/arch/arm64/include/asm/bitops.h   xen/include/asm-arm/arm64/bitops.h
 
 ---------------------------------------------------------------------
diff --git a/xen/arch/arm/arm64/lib/bitops.S b/xen/arch/arm/arm64/lib/bitops.S
deleted file mode 100644
index 6471dd1875..0000000000
--- a/xen/arch/arm/arm64/lib/bitops.S
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Based on linux/arch/arm64/lib/bitops.h which in turn is
- * Based on arch/arm/lib/bitops.h
- *
- * Copyright (C) 2013 ARM Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * x0: bits 4:0  bit offset
- *     bits 31:5 word offset
- * x1: address
- */
-	.macro	bitop, name, instr
-ENTRY(	\name	)
-	and	w3, w0, #31		// Get bit offset
-	eor	w0, w0, w3		// Clear low bits
-	mov	x2, #1
-	add	x1, x1, x0, lsr #3	// Get word offset
-	lsl	x3, x2, x3		// Create mask
-1:	ldxr	w2, [x1]
-	\instr	w2, w2, w3
-	stxr	w0, w2, [x1]
-	cbnz	w0, 1b
-	ret
-ENDPROC(\name	)
-	.endm
-
-	.macro	testop, name, instr
-ENTRY(	\name	)
-	and	w3, w0, #31		// Get bit offset
-	eor	w0, w0, w3		// Clear low bits
-	mov	x2, #1
-	add	x1, x1, x0, lsr #3	// Get word offset
-	lsl	x4, x2, x3		// Create mask
-1:	ldxr	w2, [x1]
-	lsr	w0, w2, w3		// Save old value of bit
-	\instr	w2, w2, w4		// toggle bit
-	stlxr	w5, w2, [x1]
-	cbnz	w5, 1b
-	dmb	ish
-	and	w0, w0, #1
-3:	ret
-ENDPROC(\name	)
-	.endm
-
-/*
- * Atomic bit operations.
- */
-	bitop	change_bit, eor
-	bitop	clear_bit, bic
-	bitop	set_bit, orr
-
-	testop	test_and_change_bit, eor
-	testop	test_and_clear_bit, bic
-	testop	test_and_set_bit, orr
diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
new file mode 100644
index 0000000000..b1c681c642
--- /dev/null
+++ b/xen/arch/arm/arm64/lib/bitops.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/bitops.h>
+#include <asm/system.h>
+
+/*
+ * The atomic bit operations pass the number of bit in a signed number
+ * (not sure why). This has the drawback to increase the complexity of
+ * the resulting assembly.
+ *
+ * To generate simpler code, the number of bit (nr) will be cast to
+ * unsigned int.
+ *
+ * XXX: Rework the interface to use unsigned int.
+ */
+
+#define bitop(name, instr)                                                  \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
+    unsigned long res, tmp;                                                 \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldxr    %w2, %1\n"                                              \
+        "   " __stringify(instr) "     %w2, %w2, %w3\n"                     \
+        "   stxr    %w0, %w2, %1\n"                                         \
+        : "=&r" (res), "+Q" (*ptr), "=&r" (tmp)                             \
+        : "r" (mask));                                                      \
+    } while ( res );                                                        \
+}                                                                           \
+
+#define testop(name, instr)                                                 \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
+    const uint32_t mask = BIT_MASK(bit);                                    \
+    unsigned long res, tmp;                                                 \
+    unsigned long oldbit;                                                   \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldxr    %w3, %2\n"                                              \
+        "   lsr     %w1, %w3, %w5 // Save old value of bit\n"               \
+        "   " __stringify(instr) "  %w3, %w3, %w4 // Toggle bit\n"          \
+        "   stlxr   %w0, %w3, %2\n"                                         \
+        : "=&r" (res), "=&r" (oldbit), "+Q" (*ptr), "=&r" (tmp)             \
+        : "r" (mask), "r" (bit)                                             \
+        : "memory");                                                        \
+    } while ( res );                                                        \
+                                                                            \
+    dmb(ish);                                                               \
+                                                                            \
+    return oldbit & 1;                                                      \
+}
+
+bitop(change_bit, eor)
+bitop(clear_bit, bic)
+bitop(set_bit, orr)
+
+testop(test_and_change_bit, eor)
+testop(test_and_clear_bit, bic)
+testop(test_and_set_bit, orr)
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.17.1
xsa295/4.10-06.patch (application/octet-stream, 15.5 KB)
From 7e2c0a9f08b2a68f52bb0cb11bdc3b997c603f47 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:19 +0100
Subject: [PATCH v2 4.10 06/20] xen/arm32: bitops: Rewrite bitop helpers in C

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/README.LinuxPrimitives    |  14 +---
 xen/arch/arm/arm32/lib/Makefile        |   5 +-
 xen/arch/arm/arm32/lib/bitops.c        |  98 +++++++++++++++++++++++
 xen/arch/arm/arm32/lib/bitops.h        | 104 -------------------------
 xen/arch/arm/arm32/lib/changebit.S     |  14 ----
 xen/arch/arm/arm32/lib/clearbit.S      |  14 ----
 xen/arch/arm/arm32/lib/setbit.S        |  15 ----
 xen/arch/arm/arm32/lib/testchangebit.S |  15 ----
 xen/arch/arm/arm32/lib/testclearbit.S  |  15 ----
 xen/arch/arm/arm32/lib/testsetbit.S    |  15 ----
 xen/include/asm-arm/arm32/bitops.h     |  19 ++---
 11 files changed, 108 insertions(+), 220 deletions(-)
 create mode 100644 xen/arch/arm/arm32/lib/bitops.c
 delete mode 100644 xen/arch/arm/arm32/lib/bitops.h
 delete mode 100644 xen/arch/arm/arm32/lib/changebit.S
 delete mode 100644 xen/arch/arm/arm32/lib/clearbit.S
 delete mode 100644 xen/arch/arm/arm32/lib/setbit.S
 delete mode 100644 xen/arch/arm/arm32/lib/testchangebit.S
 delete mode 100644 xen/arch/arm/arm32/lib/testclearbit.S
 delete mode 100644 xen/arch/arm/arm32/lib/testsetbit.S

diff --git a/xen/arch/arm/README.LinuxPrimitives b/xen/arch/arm/README.LinuxPrimitives
index 891667a5da..664a9f89ed 100644
--- a/xen/arch/arm/README.LinuxPrimitives
+++ b/xen/arch/arm/README.LinuxPrimitives
@@ -68,19 +68,9 @@ arm32
 
 bitops: last sync @ v3.16-rc6 (last commit: c32ffce0f66e)
 
-linux/arch/arm/lib/bitops.h             xen/arch/arm/arm32/lib/bitops.h
-linux/arch/arm/lib/changebit.S          xen/arch/arm/arm32/lib/changebit.S
-linux/arch/arm/lib/clearbit.S           xen/arch/arm/arm32/lib/clearbit.S
 linux/arch/arm/lib/findbit.S            xen/arch/arm/arm32/lib/findbit.S
-linux/arch/arm/lib/setbit.S             xen/arch/arm/arm32/lib/setbit.S
-linux/arch/arm/lib/testchangebit.S      xen/arch/arm/arm32/lib/testchangebit.S
-linux/arch/arm/lib/testclearbit.S       xen/arch/arm/arm32/lib/testclearbit.S
-linux/arch/arm/lib/testsetbit.S         xen/arch/arm/arm32/lib/testsetbit.S
-
-for i in bitops.h changebit.S clearbit.S findbit.S setbit.S testchangebit.S \
-         testclearbit.S testsetbit.S; do
-    diff -u ../linux/arch/arm/lib/$i xen/arch/arm/arm32/lib/$i;
-done
+
+diff -u ../linux/arch/arm/lib/findbit.S xen/arch/arm/arm32/lib/findbit.S
 
 ---------------------------------------------------------------------
 
diff --git a/xen/arch/arm/arm32/lib/Makefile b/xen/arch/arm/arm32/lib/Makefile
index e9fbc595b9..b1457c89dc 100644
--- a/xen/arch/arm/arm32/lib/Makefile
+++ b/xen/arch/arm/arm32/lib/Makefile
@@ -1,6 +1,5 @@
 obj-y += memcpy.o memmove.o memset.o memchr.o memzero.o
-obj-y += findbit.o setbit.o
-obj-y += setbit.o clearbit.o changebit.o
-obj-y += testsetbit.o testclearbit.o testchangebit.o
+obj-y += findbit.o
+obj-y += bitops.o
 obj-y += strchr.o strrchr.o
 obj-y += lib1funcs.o lshrdi3.o div64.o
diff --git a/xen/arch/arm/arm32/lib/bitops.c b/xen/arch/arm/arm32/lib/bitops.c
new file mode 100644
index 0000000000..c69bb53037
--- /dev/null
+++ b/xen/arch/arm/arm32/lib/bitops.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/bitops.h>
+#include <xen/prefetch.h>
+#include <asm/system.h>
+
+/*
+ * The atomic bit operations pass the number of bit in a signed number
+ * (not sure why). This has the drawback to increase the complexity of
+ * the resulting assembly.
+ *
+ * To generate simpler code, the number of bit (nr) will be cast to
+ * unsigned int.
+ *
+ * XXX: Rework the interface to use unsigned int.
+ */
+
+#define bitop(name, instr)                                                  \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
+    unsigned long res, tmp;                                                 \
+                                                                            \
+    ASSERT(((vaddr_t)p & 0x3) == 0);                                        \
+    prefetchw((const void *)ptr);                                           \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldrex   %2, %1\n"                                               \
+        "   " __stringify(instr) "     %2, %2, %3\n"                        \
+        "   strex   %0, %2, %1\n"                                           \
+        : "=&r" (res), "+Qo" (*ptr), "=&r" (tmp)                            \
+        : "r" (mask));                                                      \
+    } while ( res );                                                        \
+}
+
+#define testop(name, instr)                                                 \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
+    const uint32_t mask = BIT_MASK(bit);                                    \
+    unsigned long res, tmp;                                                 \
+    int oldbit;                                                             \
+                                                                            \
+    ASSERT(((vaddr_t)p & 0x3) == 0);                                        \
+    smp_mb();                                                               \
+                                                                            \
+    prefetchw((const void *)ptr);                                           \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldrex   %3, %2\n"                                               \
+        "   lsr     %1, %3, %5 // Save old value of bit\n"                  \
+        "   " __stringify(instr) "  %3, %3, %4 // Toggle bit\n"             \
+        "   strex  %0, %3, %2\n"                                            \
+        : "=&r" (res), "=&r" (oldbit), "+Qo" (*ptr), "=&r" (tmp)            \
+        : "r" (mask), "r" (bit));                                           \
+    } while ( res );                                                        \
+                                                                            \
+    smp_mb();                                                               \
+                                                                            \
+    return oldbit & 1;                                                      \
+}                                                                           \
+
+bitop(change_bit, eor)
+bitop(clear_bit, bic)
+bitop(set_bit, orr)
+
+testop(test_and_change_bit, eor)
+testop(test_and_clear_bit, bic)
+testop(test_and_set_bit, orr)
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/arm32/lib/bitops.h b/xen/arch/arm/arm32/lib/bitops.h
deleted file mode 100644
index d5e13476f4..0000000000
--- a/xen/arch/arm/arm32/lib/bitops.h
+++ /dev/null
@@ -1,104 +0,0 @@
-
-#if __LINUX_ARM_ARCH__ >= 6
-	.macro	bitop, name, instr
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	mov	r2, #1
-	and	r3, r0, #31		@ Get bit offset
-	mov	r0, r0, lsr #5
-	add	r1, r1, r0, lsl #2	@ Get word offset
-#if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
-	.arch_extension	mp
-	ALT_SMP(W(pldw)	[r1])
-	ALT_UP(W(nop))
-#endif
-	mov	r3, r2, lsl r3
-1:	ldrex	r2, [r1]
-	\instr	r2, r2, r3
-	strex	r0, r2, [r1]
-	cmp	r0, #0
-	bne	1b
-	bx	lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-
-	.macro	testop, name, instr, store
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	mov	r2, #1
-	and	r3, r0, #31		@ Get bit offset
-	mov	r0, r0, lsr #5
-	add	r1, r1, r0, lsl #2	@ Get word offset
-	mov	r3, r2, lsl r3		@ create mask
-	smp_dmb
-#if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
-	.arch_extension	mp
-	ALT_SMP(W(pldw)	[r1])
-	ALT_UP(W(nop))
-#endif
-1:	ldrex	r2, [r1]
-	ands	r0, r2, r3		@ save old value of bit
-	\instr	r2, r2, r3		@ toggle bit
-	strex	ip, r2, [r1]
-	cmp	ip, #0
-	bne	1b
-	smp_dmb
-	cmp	r0, #0
-	movne	r0, #1
-2:	bx	lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-#else
-	.macro	bitop, name, instr
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	and	r2, r0, #31
-	mov	r0, r0, lsr #5
-	mov	r3, #1
-	mov	r3, r3, lsl r2
-	save_and_disable_irqs ip
-	ldr	r2, [r1, r0, lsl #2]
-	\instr	r2, r2, r3
-	str	r2, [r1, r0, lsl #2]
-	restore_irqs ip
-	mov	pc, lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-
-/**
- * testop - implement a test_and_xxx_bit operation.
- * @instr: operational instruction
- * @store: store instruction
- *
- * Note: we can trivially conditionalise the store instruction
- * to avoid dirtying the data cache.
- */
-	.macro	testop, name, instr, store
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	and	r3, r0, #31
-	mov	r0, r0, lsr #5
-	save_and_disable_irqs ip
-	ldr	r2, [r1, r0, lsl #2]!
-	mov	r0, #1
-	tst	r2, r0, lsl r3
-	\instr	r2, r2, r0, lsl r3
-	\store	r2, [r1]
-	moveq	r0, #0
-	restore_irqs ip
-	mov	pc, lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-#endif
diff --git a/xen/arch/arm/arm32/lib/changebit.S b/xen/arch/arm/arm32/lib/changebit.S
deleted file mode 100644
index 6e4ae7594a..0000000000
--- a/xen/arch/arm/arm32/lib/changebit.S
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- *  linux/arch/arm/lib/changebit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-bitop	_change_bit, eor
diff --git a/xen/arch/arm/arm32/lib/clearbit.S b/xen/arch/arm/arm32/lib/clearbit.S
deleted file mode 100644
index fda553f246..0000000000
--- a/xen/arch/arm/arm32/lib/clearbit.S
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- *  linux/arch/arm/lib/clearbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-bitop	_clear_bit, bic
diff --git a/xen/arch/arm/arm32/lib/setbit.S b/xen/arch/arm/arm32/lib/setbit.S
deleted file mode 100644
index d52f0ab65c..0000000000
--- a/xen/arch/arm/arm32/lib/setbit.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- *  linux/arch/arm/lib/setbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "assembler.h"
-#include "bitops.h"
-	.text
-
-bitop	_set_bit, orr
diff --git a/xen/arch/arm/arm32/lib/testchangebit.S b/xen/arch/arm/arm32/lib/testchangebit.S
deleted file mode 100644
index d83b04c057..0000000000
--- a/xen/arch/arm/arm32/lib/testchangebit.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- *  linux/arch/arm/lib/testchangebit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-testop	_test_and_change_bit, eor, str
diff --git a/xen/arch/arm/arm32/lib/testclearbit.S b/xen/arch/arm/arm32/lib/testclearbit.S
deleted file mode 100644
index 6f5b7b92d1..0000000000
--- a/xen/arch/arm/arm32/lib/testclearbit.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- *  linux/arch/arm/lib/testclearbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-testop	_test_and_clear_bit, bicne, strne
diff --git a/xen/arch/arm/arm32/lib/testsetbit.S b/xen/arch/arm/arm32/lib/testsetbit.S
deleted file mode 100644
index 30425a842a..0000000000
--- a/xen/arch/arm/arm32/lib/testsetbit.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- *  linux/arch/arm/lib/testsetbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-testop	_test_and_set_bit, orreq, streq
diff --git a/xen/include/asm-arm/arm32/bitops.h b/xen/include/asm-arm/arm32/bitops.h
index 8be3564540..67c4c3f55c 100644
--- a/xen/include/asm-arm/arm32/bitops.h
+++ b/xen/include/asm-arm/arm32/bitops.h
@@ -1,19 +1,12 @@
 #ifndef _ARM_ARM32_BITOPS_H
 #define _ARM_ARM32_BITOPS_H
 
-extern void _set_bit(int nr, volatile void * p);
-extern void _clear_bit(int nr, volatile void * p);
-extern void _change_bit(int nr, volatile void * p);
-extern int _test_and_set_bit(int nr, volatile void * p);
-extern int _test_and_clear_bit(int nr, volatile void * p);
-extern int _test_and_change_bit(int nr, volatile void * p);
-
-#define set_bit(n,p)              _set_bit(n,p)
-#define clear_bit(n,p)            _clear_bit(n,p)
-#define change_bit(n,p)           _change_bit(n,p)
-#define test_and_set_bit(n,p)     _test_and_set_bit(n,p)
-#define test_and_clear_bit(n,p)   _test_and_clear_bit(n,p)
-#define test_and_change_bit(n,p)  _test_and_change_bit(n,p)
+extern void set_bit(int nr, volatile void * p);
+extern void clear_bit(int nr, volatile void * p);
+extern void change_bit(int nr, volatile void * p);
+extern int test_and_set_bit(int nr, volatile void * p);
+extern int test_and_clear_bit(int nr, volatile void * p);
+extern int test_and_change_bit(int nr, volatile void * p);
 
 #define flsl fls
 
-- 
2.17.1
xsa295/4.10-07.patch (application/octet-stream, 2.7 KB)
From 7cafbff13b636f159204d23540ad7bbdbaa07ce8 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:20 +0100
Subject: [PATCH v2 4.10 07/20] xen/arm: bitops: Consolidate prototypes in one
 place

The prototype are the same between arm32 and arm64. Consolidate them in
asm-arm/bitops.h.

This change will help the introductions of new helpers in a follow-up
patch.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm32/bitops.h |  7 -------
 xen/include/asm-arm/arm64/bitops.h | 10 ----------
 xen/include/asm-arm/bitops.h       |  8 ++++++++
 3 files changed, 8 insertions(+), 17 deletions(-)

diff --git a/xen/include/asm-arm/arm32/bitops.h b/xen/include/asm-arm/arm32/bitops.h
index 67c4c3f55c..57938a5874 100644
--- a/xen/include/asm-arm/arm32/bitops.h
+++ b/xen/include/asm-arm/arm32/bitops.h
@@ -1,13 +1,6 @@
 #ifndef _ARM_ARM32_BITOPS_H
 #define _ARM_ARM32_BITOPS_H
 
-extern void set_bit(int nr, volatile void * p);
-extern void clear_bit(int nr, volatile void * p);
-extern void change_bit(int nr, volatile void * p);
-extern int test_and_set_bit(int nr, volatile void * p);
-extern int test_and_clear_bit(int nr, volatile void * p);
-extern int test_and_change_bit(int nr, volatile void * p);
-
 #define flsl fls
 
 /*
diff --git a/xen/include/asm-arm/arm64/bitops.h b/xen/include/asm-arm/arm64/bitops.h
index 6bf1922680..6cc224ad13 100644
--- a/xen/include/asm-arm/arm64/bitops.h
+++ b/xen/include/asm-arm/arm64/bitops.h
@@ -1,16 +1,6 @@
 #ifndef _ARM_ARM64_BITOPS_H
 #define _ARM_ARM64_BITOPS_H
 
-/*
- * Little endian assembly atomic bitops.
- */
-extern void set_bit(int nr, volatile void *p);
-extern void clear_bit(int nr, volatile void *p);
-extern void change_bit(int nr, volatile void *p);
-extern int test_and_set_bit(int nr, volatile void *p);
-extern int test_and_clear_bit(int nr, volatile void *p);
-extern int test_and_change_bit(int nr, volatile void *p);
-
 /* Based on linux/include/asm-generic/bitops/builtin-__ffs.h */
 /**
  * __ffs - find first bit in word.
diff --git a/xen/include/asm-arm/bitops.h b/xen/include/asm-arm/bitops.h
index 1cbfb9edb2..c69b08adf6 100644
--- a/xen/include/asm-arm/bitops.h
+++ b/xen/include/asm-arm/bitops.h
@@ -38,6 +38,14 @@
 # error "unknown ARM variant"
 #endif
 
+/* Atomics bitops */
+void set_bit(int nr, volatile void *p);
+void clear_bit(int nr, volatile void *p);
+void change_bit(int nr, volatile void *p);
+int test_and_set_bit(int nr, volatile void *p);
+int test_and_clear_bit(int nr, volatile void *p);
+int test_and_change_bit(int nr, volatile void *p);
+
 /**
  * __test_and_set_bit - Set a bit and return its old value
  * @nr: Bit to set
-- 
2.17.1
xsa295/4.10-08.patch (application/octet-stream, 3.7 KB)
From 0b005e118190e19b4d8c6c21791441a59eb8220e Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Wed, 22 May 2019 13:37:53 -0700
Subject: [PATCH v2 4.10 08/20] xen/arm64: cmpxchg: Simplify the cmpxchg
 implementation

The only difference between each case of the cmpxchg is the size of
used. Rather than duplicating the code, provide a macro to generate each
cases.

This makes the code easier to read and modify.

This is part of XSA-295.

Signed-off-by; Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm64/cmpxchg.h | 98 +++++++++++------------------
 1 file changed, 36 insertions(+), 62 deletions(-)

diff --git a/xen/include/asm-arm/arm64/cmpxchg.h b/xen/include/asm-arm/arm64/cmpxchg.h
index ae42b2f5ff..393fbca6a5 100644
--- a/xen/include/asm-arm/arm64/cmpxchg.h
+++ b/xen/include/asm-arm/arm64/cmpxchg.h
@@ -61,80 +61,54 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
 	__ret; \
 })
 
-extern void __bad_cmpxchg(volatile void *ptr, int size);
+extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
+
+#define __CMPXCHG_CASE(w, sz, name)					\
+static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
+						  unsigned long old,	\
+						  unsigned long new)	\
+{									\
+	unsigned long res, oldval;					\
+									\
+	do {								\
+		asm volatile("// __cmpxchg_case_" #name "\n"		\
+		"	ldxr" #sz "	%" #w "1, %2\n"			\
+		"	mov	%w0, #0\n"				\
+		"	cmp	%" #w "1, %" #w "3\n"			\
+		"	b.ne	1f\n"					\
+		"	stxr" #sz "	%w0, %" #w "4, %2\n"		\
+		"1:\n"							\
+		: "=&r" (res), "=&r" (oldval),				\
+		  "+Q" (*(unsigned long *)ptr)				\
+		: "Ir" (old), "r" (new)					\
+		: "cc");						\
+	} while (res);							\
+									\
+	return oldval;							\
+}
+
+__CMPXCHG_CASE(w, b, 1)
+__CMPXCHG_CASE(w, h, 2)
+__CMPXCHG_CASE(w,  , 4)
+__CMPXCHG_CASE( ,  , 8)
 
 static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 				      unsigned long new, int size)
 {
-	unsigned long oldval = 0, res;
-
 	switch (size) {
 	case 1:
-		do {
-			asm volatile("// __cmpxchg1\n"
-			"	ldxrb	%w1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%w1, %w3\n"
-			"	b.ne	1f\n"
-			"	stxrb	%w0, %w4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u8 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_1(ptr, old, new);
 	case 2:
-		do {
-			asm volatile("// __cmpxchg2\n"
-			"	ldxrh	%w1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%w1, %w3\n"
-			"	b.ne	1f\n"
-			"	stxrh	%w0, %w4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u16 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_2(ptr, old, new);
 	case 4:
-		do {
-			asm volatile("// __cmpxchg4\n"
-			"	ldxr	%w1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%w1, %w3\n"
-			"	b.ne	1f\n"
-			"	stxr	%w0, %w4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u32 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_4(ptr, old, new);
 	case 8:
-		do {
-			asm volatile("// __cmpxchg8\n"
-			"	ldxr	%1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%1, %3\n"
-			"	b.ne	1f\n"
-			"	stxr	%w0, %4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u64 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_8(ptr, old, new);
 	default:
-		__bad_cmpxchg(ptr, size);
-		oldval = 0;
+		return __bad_cmpxchg(ptr, size);
 	}
 
-	return oldval;
+	ASSERT_UNREACHABLE();
 }
 
 static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
-- 
2.17.1
xsa295/4.10-09.patch (application/octet-stream, 3.6 KB)
From cd09ddf77ec2335ae2ed093307cb5cea80782fb5 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:22 +0100
Subject: [PATCH v2 4.10 09/20] xen/arm32: cmpxchg: Simplify the cmpxchg
 implementation

The only difference between each case of the cmpxchg is the size of
used. Rather than duplicating the code, provide a macro to generate each
cases.

This makes the code easier to read and modify.

While doing the rework, the case for 64-bit cmpxchg is removed. This is
unused today (already commented) and it would not be possible to use
it directly.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm32/cmpxchg.h | 84 +++++++++++------------------
 1 file changed, 31 insertions(+), 53 deletions(-)

diff --git a/xen/include/asm-arm/arm32/cmpxchg.h b/xen/include/asm-arm/arm32/cmpxchg.h
index 03e0bed3a6..471a9e3a3f 100644
--- a/xen/include/asm-arm/arm32/cmpxchg.h
+++ b/xen/include/asm-arm/arm32/cmpxchg.h
@@ -52,72 +52,50 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
  * indicated by comparing RETURN with OLD.
  */
 
-extern void __bad_cmpxchg(volatile void *ptr, int size);
+extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
+
+#define __CMPXCHG_CASE(sz, name)					\
+static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
+						  unsigned long old,	\
+						  unsigned long new)	\
+{									\
+	unsigned long oldval, res;					\
+									\
+	do {								\
+		asm volatile("@ __cmpxchg_case_" #name "\n"		\
+		"	ldrex" #sz "	%1, [%2]\n"			\
+		"	mov	%0, #0\n"				\
+		"	teq	%1, %3\n"				\
+		"	strex" #sz "eq %0, %4, [%2]\n"			\
+		: "=&r" (res), "=&r" (oldval)				\
+		: "r" (ptr), "Ir" (old), "r" (new)			\
+		: "memory", "cc");					\
+	} while (res);							\
+									\
+	return oldval;							\
+}
+
+__CMPXCHG_CASE(b, 1)
+__CMPXCHG_CASE(h, 2)
+__CMPXCHG_CASE( , 4)
 
 static always_inline unsigned long __cmpxchg(
     volatile void *ptr, unsigned long old, unsigned long new, int size)
 {
-	unsigned long oldval, res;
-
 	prefetchw((const void *)ptr);
 
 	switch (size) {
 	case 1:
-		do {
-			asm volatile("@ __cmpxchg1\n"
-			"	ldrexb	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexbeq %0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-		} while (res);
-		break;
+		return __cmpxchg_case_1(ptr, old, new);
 	case 2:
-		do {
-			asm volatile("@ __cmpxchg2\n"
-			"	ldrexh	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexheq %0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-		} while (res);
-		break;
+		return __cmpxchg_case_2(ptr, old, new);
 	case 4:
-		do {
-			asm volatile("@ __cmpxchg4\n"
-			"	ldrex	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexeq	%0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-	    } while (res);
-	    break;
-#if 0
-	case 8:
-		do {
-			asm volatile("@ __cmpxchg8\n"
-			"	ldrexd	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexdeq %0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-		} while (res);
-		break;
-#endif
+		return __cmpxchg_case_4(ptr, old, new);
 	default:
-		__bad_cmpxchg(ptr, size);
-		oldval = 0;
+		return __bad_cmpxchg(ptr, size);
 	}
 
-	return oldval;
+	ASSERT_UNREACHABLE();
 }
 
 static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
-- 
2.17.1
xsa295/4.10-10.patch (application/octet-stream, 15.3 KB)
From 776dea812bf73c8bde42a91100c114383e67164c Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:23 +0100
Subject: [PATCH v2 4.10 10/20] xen/arm: bitops: Implement a new set of helpers
 that can timeout

Exclusive load-store atomics should only be used between trusted
threads. As not all the guests are trusted, it may be possible to DoS
Xen when updating shared memory with guest atomically.

To prevent the infinite loop, we introduce a new set of helpers that can
timeout. The timeout is based on the maximum number of iterations.

They will be used in follow-up patch to make atomic operations
on shared memory safe.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/arm32/lib/bitops.c | 52 ++++++++++++++++++++++++++++-----
 xen/arch/arm/arm64/lib/bitops.c | 52 ++++++++++++++++++++++++++++-----
 xen/include/asm-arm/bitops.h    | 28 +++++++++++++++++-
 3 files changed, 117 insertions(+), 15 deletions(-)

diff --git a/xen/arch/arm/arm32/lib/bitops.c b/xen/arch/arm/arm32/lib/bitops.c
index c69bb53037..08750314fc 100644
--- a/xen/arch/arm/arm32/lib/bitops.c
+++ b/xen/arch/arm/arm32/lib/bitops.c
@@ -30,7 +30,8 @@
  */
 
 #define bitop(name, instr)                                                  \
-void name(int nr, volatile void *p)                                         \
+static always_inline bool int_##name(int nr, volatile void *p, bool timeout,\
+                                     unsigned int max_try)                  \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
@@ -47,17 +48,33 @@ void name(int nr, volatile void *p)                                         \
         "   strex   %0, %2, %1\n"                                           \
         : "=&r" (res), "+Qo" (*ptr), "=&r" (tmp)                            \
         : "r" (mask));                                                      \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
+                                                                            \
+    return !res;                                                            \
+}                                                                           \
+                                                                            \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    if ( !int_##name(nr, p, false, 0) )                                     \
+        ASSERT_UNREACHABLE();                                               \
+}                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p, unsigned int max_try)         \
+{                                                                           \
+    return int_##name(nr, p, true, max_try);                                \
 }
 
 #define testop(name, instr)                                                 \
-int name(int nr, volatile void *p)                                          \
+static always_inline bool int_##name(int nr, volatile void *p, int *oldbit, \
+                                     bool timeout, unsigned int max_try)    \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
     const uint32_t mask = BIT_MASK(bit);                                    \
     unsigned long res, tmp;                                                 \
-    int oldbit;                                                             \
                                                                             \
     ASSERT(((vaddr_t)p & 0x3) == 0);                                        \
     smp_mb();                                                               \
@@ -71,14 +88,35 @@ int name(int nr, volatile void *p)                                          \
         "   lsr     %1, %3, %5 // Save old value of bit\n"                  \
         "   " __stringify(instr) "  %3, %3, %4 // Toggle bit\n"             \
         "   strex  %0, %3, %2\n"                                            \
-        : "=&r" (res), "=&r" (oldbit), "+Qo" (*ptr), "=&r" (tmp)            \
+        : "=&r" (res), "=&r" (*oldbit), "+Qo" (*ptr), "=&r" (tmp)           \
         : "r" (mask), "r" (bit));                                           \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
                                                                             \
     smp_mb();                                                               \
                                                                             \
-    return oldbit & 1;                                                      \
+    *oldbit &= 1;                                                           \
+                                                                            \
+    return !res;                                                            \
+}                                                                           \
+                                                                            \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    int oldbit;                                                             \
+                                                                            \
+    if ( !int_##name(nr, p, &oldbit, false, 0) )                            \
+        ASSERT_UNREACHABLE();                                               \
+                                                                            \
+    return oldbit;                                                          \
 }                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p,                               \
+                    int *oldbit, unsigned int max_try)                      \
+{                                                                           \
+    return int_##name(nr, p, oldbit, true, max_try);                        \
+}
 
 bitop(change_bit, eor)
 bitop(clear_bit, bic)
diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
index b1c681c642..78bf4ed8c5 100644
--- a/xen/arch/arm/arm64/lib/bitops.c
+++ b/xen/arch/arm/arm64/lib/bitops.c
@@ -29,7 +29,8 @@
  */
 
 #define bitop(name, instr)                                                  \
-void name(int nr, volatile void *p)                                         \
+static always_inline bool int_##name(int nr, volatile void *p, bool timeout,\
+                                     unsigned int max_try)                  \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
@@ -43,17 +44,33 @@ void name(int nr, volatile void *p)                                         \
         "   stxr    %w0, %w2, %1\n"                                         \
         : "=&r" (res), "+Q" (*ptr), "=&r" (tmp)                             \
         : "r" (mask));                                                      \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
+                                                                            \
+    return !res;                                                            \
 }                                                                           \
+                                                                            \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    if ( !int_##name(nr, p, false, 0) )                                     \
+        ASSERT_UNREACHABLE();                                               \
+}                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p, unsigned int max_try)         \
+{                                                                           \
+    return int_##name(nr, p, true, max_try);                                \
+}
 
 #define testop(name, instr)                                                 \
-int name(int nr, volatile void *p)                                          \
+static always_inline bool int_##name(int nr, volatile void *p, int *oldbit, \
+                                     bool timeout, unsigned int max_try)    \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
     const uint32_t mask = BIT_MASK(bit);                                    \
     unsigned long res, tmp;                                                 \
-    unsigned long oldbit;                                                   \
                                                                             \
     do                                                                      \
     {                                                                       \
@@ -62,14 +79,35 @@ int name(int nr, volatile void *p)                                          \
         "   lsr     %w1, %w3, %w5 // Save old value of bit\n"               \
         "   " __stringify(instr) "  %w3, %w3, %w4 // Toggle bit\n"          \
         "   stlxr   %w0, %w3, %2\n"                                         \
-        : "=&r" (res), "=&r" (oldbit), "+Q" (*ptr), "=&r" (tmp)             \
+        : "=&r" (res), "=&r" (*oldbit), "+Q" (*ptr), "=&r" (tmp)            \
         : "r" (mask), "r" (bit)                                             \
         : "memory");                                                        \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
                                                                             \
     dmb(ish);                                                               \
                                                                             \
-    return oldbit & 1;                                                      \
+    *oldbit &= 1;                                                           \
+                                                                            \
+    return !res;                                                            \
+}                                                                           \
+                                                                            \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    int oldbit;                                                             \
+                                                                            \
+    if ( !int_##name(nr, p, &oldbit, false, 0) )                            \
+        ASSERT_UNREACHABLE();                                               \
+                                                                            \
+    return oldbit;                                                          \
+}                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p,                               \
+                    int *oldbit, unsigned int max_try)                      \
+{                                                                           \
+    return int_##name(nr, p, oldbit, true, max_try);                        \
 }
 
 bitop(change_bit, eor)
diff --git a/xen/include/asm-arm/bitops.h b/xen/include/asm-arm/bitops.h
index c69b08adf6..f6782b33be 100644
--- a/xen/include/asm-arm/bitops.h
+++ b/xen/include/asm-arm/bitops.h
@@ -38,7 +38,14 @@
 # error "unknown ARM variant"
 #endif
 
-/* Atomics bitops */
+/*
+ * Atomic bitops
+ *
+ * The helpers below *should* only be used on memory shared between
+ * trusted threads or we know the memory cannot be accessed by another
+ * thread.
+ */
+
 void set_bit(int nr, volatile void *p);
 void clear_bit(int nr, volatile void *p);
 void change_bit(int nr, volatile void *p);
@@ -46,6 +53,25 @@ int test_and_set_bit(int nr, volatile void *p);
 int test_and_clear_bit(int nr, volatile void *p);
 int test_and_change_bit(int nr, volatile void *p);
 
+/*
+ * The helpers below may fail to update the memory if the action takes
+ * too long.
+ *
+ * @max_try: Maximum number of iterations
+ *
+ * The helpers will return true when the update has succeeded (i.e no
+ * timeout) and false if the update has failed.
+ */
+bool set_bit_timeout(int nr, volatile void *p, unsigned int max_try);
+bool clear_bit_timeout(int nr, volatile void *p, unsigned int max_try);
+bool change_bit_timeout(int nr, volatile void *p, unsigned int max_try);
+bool test_and_set_bit_timeout(int nr, volatile void *p,
+                              int *oldbit, unsigned int max_try);
+bool test_and_clear_bit_timeout(int nr, volatile void *p,
+                                int *oldbit, unsigned int max_try);
+bool test_and_change_bit_timeout(int nr, volatile void *p,
+                                 int *oldbit, unsigned int max_try);
+
 /**
  * __test_and_set_bit - Set a bit and return its old value
  * @nr: Bit to set
-- 
2.17.1
xsa295/4.10-11.patch (application/octet-stream, 8.3 KB)
From 730772cf0ea3c9876af389b4d0d84ee74d78e963 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Wed, 22 May 2019 13:39:17 -0700
Subject: [PATCH v2 4.10 11/20] xen/arm: cmpxchg: Provide a new helper that can
 timeout

Exclusive load-store atomics should only be used between trusted
threads. As not all the guests are trusted, it may be possible to DoS
Xen when updating shared memory with guest atomically.

To prevent the infinite loop, we introduce a new helper that can timeout.
The timeout is based on the maximum number of iterations.

It will be used in follow-up patch to make atomic operations on shared
memory safe.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm32/cmpxchg.h | 63 +++++++++++++++++++++-----
 xen/include/asm-arm/arm64/cmpxchg.h | 70 ++++++++++++++++++++++-------
 2 files changed, 106 insertions(+), 27 deletions(-)

diff --git a/xen/include/asm-arm/arm32/cmpxchg.h b/xen/include/asm-arm/arm32/cmpxchg.h
index 471a9e3a3f..49ca2a0d7a 100644
--- a/xen/include/asm-arm/arm32/cmpxchg.h
+++ b/xen/include/asm-arm/arm32/cmpxchg.h
@@ -55,11 +55,14 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
 extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
 
 #define __CMPXCHG_CASE(sz, name)					\
-static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
-						  unsigned long old,	\
-						  unsigned long new)	\
+static inline bool __cmpxchg_case_##name(volatile void *ptr,		\
+					 unsigned long *old,		\
+					 unsigned long new,		\
+					 bool timeout,			\
+					 unsigned int max_try)		\
 {									\
-	unsigned long oldval, res;					\
+	unsigned long oldval;						\
+	unsigned long res;						\
 									\
 	do {								\
 		asm volatile("@ __cmpxchg_case_" #name "\n"		\
@@ -68,29 +71,35 @@ static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
 		"	teq	%1, %3\n"				\
 		"	strex" #sz "eq %0, %4, [%2]\n"			\
 		: "=&r" (res), "=&r" (oldval)				\
-		: "r" (ptr), "Ir" (old), "r" (new)			\
+		: "r" (ptr), "Ir" (*old), "r" (new)			\
 		: "memory", "cc");					\
-	} while (res);							\
 									\
-	return oldval;							\
+		if (!res)						\
+			break;						\
+	} while (!timeout || ((--max_try) > 0));			\
+									\
+	*old = oldval;							\
+									\
+	return !res;							\
 }
 
 __CMPXCHG_CASE(b, 1)
 __CMPXCHG_CASE(h, 2)
 __CMPXCHG_CASE( , 4)
 
-static always_inline unsigned long __cmpxchg(
-    volatile void *ptr, unsigned long old, unsigned long new, int size)
+static always_inline bool __int_cmpxchg(volatile void *ptr, unsigned long *old,
+					unsigned long new, int size,
+					bool timeout, unsigned int max_try)
 {
 	prefetchw((const void *)ptr);
 
 	switch (size) {
 	case 1:
-		return __cmpxchg_case_1(ptr, old, new);
+		return __cmpxchg_case_1(ptr, old, new, timeout, max_try);
 	case 2:
-		return __cmpxchg_case_2(ptr, old, new);
+		return __cmpxchg_case_2(ptr, old, new, timeout, max_try);
 	case 4:
-		return __cmpxchg_case_4(ptr, old, new);
+		return __cmpxchg_case_4(ptr, old, new, timeout, max_try);
 	default:
 		return __bad_cmpxchg(ptr, size);
 	}
@@ -98,6 +107,17 @@ static always_inline unsigned long __cmpxchg(
 	ASSERT_UNREACHABLE();
 }
 
+static always_inline unsigned long __cmpxchg(volatile void *ptr,
+					     unsigned long old,
+					     unsigned long new,
+					     int size)
+{
+	if (!__int_cmpxchg(ptr, &old, new, size, false, 0))
+		ASSERT_UNREACHABLE();
+
+	return old;
+}
+
 static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
                                                 unsigned long old,
                                                 unsigned long new, int size)
@@ -111,6 +131,25 @@ static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
 	return ret;
 }
 
+/*
+ * The helper may fail to update the memory if the action takes too long.
+ *
+ * @old: On call the value pointed contains the expected old value. It will be
+ * updated to the actual old value.
+ * @max_try: Maximum number of iterations
+ *
+ * The helper will return true when the update has succeeded (i.e no
+ * timeout) and false if the update has failed.
+ */
+static always_inline bool __cmpxchg_mb_timeout(volatile void *ptr,
+					       unsigned long *old,
+					       unsigned long new,
+					       int size,
+					       unsigned int max_try)
+{
+	return __int_cmpxchg(ptr, old, new, size, true, max_try);
+}
+
 #define cmpxchg(ptr,o,n)						\
 	((__typeof__(*(ptr)))__cmpxchg_mb((ptr),			\
 					  (unsigned long)(o),		\
diff --git a/xen/include/asm-arm/arm64/cmpxchg.h b/xen/include/asm-arm/arm64/cmpxchg.h
index 393fbca6a5..5bc2e1f786 100644
--- a/xen/include/asm-arm/arm64/cmpxchg.h
+++ b/xen/include/asm-arm/arm64/cmpxchg.h
@@ -64,11 +64,14 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
 extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
 
 #define __CMPXCHG_CASE(w, sz, name)					\
-static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
-						  unsigned long old,	\
-						  unsigned long new)	\
+static inline bool __cmpxchg_case_##name(volatile void *ptr,		\
+					 unsigned long *old,		\
+					 unsigned long new,		\
+					 bool timeout,			\
+					 unsigned int max_try)		\
 {									\
-	unsigned long res, oldval;					\
+	unsigned long oldval;						\
+	unsigned long res;						\
 									\
 	do {								\
 		asm volatile("// __cmpxchg_case_" #name "\n"		\
@@ -80,11 +83,16 @@ static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
 		"1:\n"							\
 		: "=&r" (res), "=&r" (oldval),				\
 		  "+Q" (*(unsigned long *)ptr)				\
-		: "Ir" (old), "r" (new)					\
+		: "Ir" (*old), "r" (new)				\
 		: "cc");						\
-	} while (res);							\
 									\
-	return oldval;							\
+		if (!res)						\
+			break;						\
+	} while (!timeout || ((--max_try) > 0));			\
+									\
+	*old = oldval;							\
+									\
+	return !res;							\
 }
 
 __CMPXCHG_CASE(w, b, 1)
@@ -92,18 +100,19 @@ __CMPXCHG_CASE(w, h, 2)
 __CMPXCHG_CASE(w,  , 4)
 __CMPXCHG_CASE( ,  , 8)
 
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
-				      unsigned long new, int size)
+static always_inline bool __int_cmpxchg(volatile void *ptr, unsigned long *old,
+					unsigned long new, int size,
+					bool timeout, unsigned int max_try)
 {
 	switch (size) {
 	case 1:
-		return __cmpxchg_case_1(ptr, old, new);
+		return __cmpxchg_case_1(ptr, old, new, timeout, max_try);
 	case 2:
-		return __cmpxchg_case_2(ptr, old, new);
+		return __cmpxchg_case_2(ptr, old, new, timeout, max_try);
 	case 4:
-		return __cmpxchg_case_4(ptr, old, new);
+		return __cmpxchg_case_4(ptr, old, new, timeout, max_try);
 	case 8:
-		return __cmpxchg_case_8(ptr, old, new);
+		return __cmpxchg_case_8(ptr, old, new, timeout, max_try);
 	default:
 		return __bad_cmpxchg(ptr, size);
 	}
@@ -111,8 +120,20 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 	ASSERT_UNREACHABLE();
 }
 
-static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
-					 unsigned long new, int size)
+static always_inline unsigned long __cmpxchg(volatile void *ptr,
+					     unsigned long old,
+					     unsigned long new,
+					     int size)
+{
+	if (!__int_cmpxchg(ptr, &old, new, size, false, 0))
+		ASSERT_UNREACHABLE();
+
+	return old;
+}
+
+static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
+						unsigned long old,
+						unsigned long new, int size)
 {
 	unsigned long ret;
 
@@ -123,6 +144,25 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
 	return ret;
 }
 
+/*
+ * The helper may fail to update the memory if the action takes too long.
+ *
+ * @old: On call the value pointed contains the expected old value. It will be
+ * updated to the actual old value.
+ * @max_try: Maximum number of iterations
+ *
+ * The helper will return true when the update has succeeded (i.e no
+ * timeout) and false if the update has failed.
+ */
+static always_inline bool __cmpxchg_mb_timeout(volatile void *ptr,
+					       unsigned long *old,
+					       unsigned long new,
+					       int size,
+					       unsigned int max_try)
+{
+	return __int_cmpxchg(ptr, old, new, size, true, max_try);
+}
+
 #define cmpxchg(ptr, o, n) \
 ({ \
 	__typeof__(*(ptr)) __ret; \
-- 
2.17.1
xsa295/4.10-12.patch (application/octet-stream, 807 B)
From 6e1c08e29a650efc0758842b33e7adbe4537a9d3 Mon Sep 17 00:00:00 2001
From: Xin Li <[email protected]>
Date: Tue, 9 Oct 2018 17:33:18 +0800
Subject: [PATCH v2 4.10 12/20] xen/xsm: remove unnecessary #define

this #define is unnecessary since XSM_INLINE is redefined in
xsm/dummy.h, it's a risk of build breakage, so remove it.

Signed-off-by: Xin Li <[email protected]>
Reviewed-by: Jan Beulich <[email protected]>
Acked-by: Daniel De Graaf <[email protected]>
---
 xen/xsm/dummy.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c
index 479b103614..3202645763 100644
--- a/xen/xsm/dummy.c
+++ b/xen/xsm/dummy.c
@@ -11,7 +11,6 @@
  */
 
 #define XSM_NO_WRAPPERS
-#define XSM_INLINE /* */
 #include <xsm/dummy.h>
 
 struct xsm_operations dummy_xsm_ops;
-- 
2.17.1
xsa295/4.10-13.patch (application/octet-stream, 3.8 KB)
From 3fd04223f9b717e3e8872a1a08c4a983b6f5f551 Mon Sep 17 00:00:00 2001
From: Xin Li <[email protected]>
Date: Tue, 9 Oct 2018 17:33:19 +0800
Subject: [PATCH v2 4.10 13/20] xen/xsm: Introduce new boot parameter xsm

Introduce new boot parameter xsm to choose which xsm module is enabled,
and set default to dummy. And add new option in Kconfig to choose the
default XSM implementation.

Signed-off-by: Xin Li <[email protected]>
Acked-by: Daniel De Graaf <[email protected]>
Acked-by: Andrew Cooper <[email protected]>
---
 docs/misc/xen-command-line.markdown | 13 +++++++++
 xen/common/Kconfig                  | 13 ++++++++-
 xen/xsm/xsm_core.c                  | 44 ++++++++++++++++++++++++++++-
 3 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/docs/misc/xen-command-line.markdown b/docs/misc/xen-command-line.markdown
index b79b340dd4..f89ab0a126 100644
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -838,6 +838,19 @@ hardware domain is architecture dependent.
 Note that specifying zero as domU value means zero, while for dom0 it means
 to use the default.
 
+### xsm
+> `= dummy | flask`
+
+> Default: `dummy`
+
+Specify which XSM module should be enabled.  This option is only available if
+the hypervisor was compiled with XSM support.
+
+* `dummy`: this is the default choice.  Basic restriction for common deployment
+  (the dummy module) will be applied.  It's also used when XSM is compiled out.
+* `flask`: this is the policy based access control.  To choose this, the
+  separated option in kconfig must also be enabled.
+
 ### flask
 > `= permissive | enforcing | late | disabled`
 
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index 103ef44cb5..da7002ace4 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -102,7 +102,7 @@ config XSM
 
 config FLASK
 	def_bool y
-	prompt "FLux Advanced Security Kernel support" if EXPERT = "y"
+	prompt "FLux Advanced Security Kernel support"
 	depends on XSM
 	---help---
 	  Enables FLASK (FLux Advanced Security Kernel) as the access control
@@ -140,6 +140,17 @@ config XSM_POLICY
 
 	  If unsure, say Y.
 
+choice
+	prompt "Default XSM implementation"
+	depends on XSM
+	default XSM_FLASK_DEFAULT if XSM_FLASK
+	default XSM_DUMMY_DEFAULT
+	config XSM_DUMMY_DEFAULT
+		bool "Match non-XSM behavior"
+	config XSM_FLASK_DEFAULT
+		bool "FLux Advanced Security Kernel" if XSM_FLASK
+endchoice
+
 config LATE_HWDOM
 	bool "Dedicated hardware domain"
 	default n
diff --git a/xen/xsm/xsm_core.c b/xen/xsm/xsm_core.c
index 08994ee7a1..e78f7d8ca2 100644
--- a/xen/xsm/xsm_core.c
+++ b/xen/xsm/xsm_core.c
@@ -27,6 +27,35 @@
 
 struct xsm_operations *xsm_ops;
 
+enum xsm_bootparam {
+    XSM_BOOTPARAM_DUMMY,
+    XSM_BOOTPARAM_FLASK,
+};
+
+static enum xsm_bootparam __initdata xsm_bootparam =
+#ifdef CONFIG_XSM_FLASK_DEFAULT
+    XSM_BOOTPARAM_FLASK;
+#else
+    XSM_BOOTPARAM_DUMMY;
+#endif
+
+static int __init parse_xsm_param(const char *s)
+{
+    int rc = 0;
+
+    if ( !strcmp(s, "dummy") )
+        xsm_bootparam = XSM_BOOTPARAM_DUMMY;
+#ifdef CONFIG_XSM_FLASK
+    else if ( !strcmp(s, "flask") )
+        xsm_bootparam = XSM_BOOTPARAM_FLASK;
+#endif
+    else
+        rc = -EINVAL;
+
+    return rc;
+}
+custom_param("xsm", parse_xsm_param);
+
 static inline int verify(struct xsm_operations *ops)
 {
     /* verify the security_operations structure exists */
@@ -53,7 +82,20 @@ static int __init xsm_core_init(const void *policy_buffer, size_t policy_size)
     }
 
     xsm_ops = &dummy_xsm_ops;
-    flask_init(policy_buffer, policy_size);
+
+    switch ( xsm_bootparam )
+    {
+    case XSM_BOOTPARAM_DUMMY:
+        break;
+
+    case XSM_BOOTPARAM_FLASK:
+        flask_init(policy_buffer, policy_size);
+        break;
+
+    default:
+        ASSERT_UNREACHABLE();
+        break;
+    }
 
     return 0;
 }
-- 
2.17.1
xsa295/4.10-14.patch (application/octet-stream, 8.3 KB)
From d3f0edcfd09175da848455bbe4ddc5f174598f3f Mon Sep 17 00:00:00 2001
From: Xin Li <[email protected]>
Date: Tue, 9 Oct 2018 17:33:20 +0800
Subject: [PATCH v2 4.10 14/20] xen/xsm: Add new SILO mode for XSM

When SILO is enabled, there would be no page-sharing or event notifications
between unprivileged VMs (no grant tables or event channels).

Signed-off-by: Xin Li <[email protected]>
Acked-by: Daniel De Graaf <[email protected]>
Acked-by: Andrew Cooper <[email protected]>
---
 docs/misc/xen-command-line.markdown |   5 +-
 xen/common/Kconfig                  |  15 ++++
 xen/include/xsm/dummy.h             |   3 +-
 xen/include/xsm/xsm.h               |   6 ++
 xen/xsm/Makefile                    |   1 +
 xen/xsm/silo.c                      | 108 ++++++++++++++++++++++++++++
 xen/xsm/xsm_core.c                  |  11 +++
 7 files changed, 147 insertions(+), 2 deletions(-)
 create mode 100644 xen/xsm/silo.c

diff --git a/docs/misc/xen-command-line.markdown b/docs/misc/xen-command-line.markdown
index f89ab0a126..0cbfb5096c 100644
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -839,7 +839,7 @@ Note that specifying zero as domU value means zero, while for dom0 it means
 to use the default.
 
 ### xsm
-> `= dummy | flask`
+> `= dummy | flask | silo`
 
 > Default: `dummy`
 
@@ -850,6 +850,9 @@ the hypervisor was compiled with XSM support.
   (the dummy module) will be applied.  It's also used when XSM is compiled out.
 * `flask`: this is the policy based access control.  To choose this, the
   separated option in kconfig must also be enabled.
+* `silo`: this will deny any unmediated communication channels between
+  unprivileged VMs.  To choose this, the separated option in kconfig must also
+  be enabled.
 
 ### flask
 > `= permissive | enforcing | late | disabled`
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index da7002ace4..43810fc026 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -140,15 +140,30 @@ config XSM_POLICY
 
 	  If unsure, say Y.
 
+config XSM_SILO
+	def_bool y
+	prompt "SILO support"
+	depends on XSM
+	---help---
+	  Enables SILO as the access control mechanism used by the XSM framework.
+	  This is not the default module, add boot parameter xsm=silo to choose
+	  it. This will deny any unmediated communication channels (grant tables
+	  and event channels) between unprivileged VMs.
+
+	  If unsure, say Y.
+
 choice
 	prompt "Default XSM implementation"
 	depends on XSM
 	default XSM_FLASK_DEFAULT if XSM_FLASK
+	default XSM_SILO_DEFAULT if XSM_SILO
 	default XSM_DUMMY_DEFAULT
 	config XSM_DUMMY_DEFAULT
 		bool "Match non-XSM behavior"
 	config XSM_FLASK_DEFAULT
 		bool "FLux Advanced Security Kernel" if XSM_FLASK
+	config XSM_SILO_DEFAULT
+		bool "SILO" if XSM_SILO
 endchoice
 
 config LATE_HWDOM
diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h
index b2cd56cdc5..1e23a665e1 100644
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -34,7 +34,8 @@ void __xsm_action_mismatch_detected(void);
  * There is no xsm_default_t argument available, so the value from the assertion
  * is used to initialize the variable.
  */
-#define XSM_INLINE /* */
+#define XSM_INLINE __maybe_unused
+
 #define XSM_DEFAULT_ARG /* */
 #define XSM_DEFAULT_VOID void
 #define XSM_ASSERT_ACTION(def) xsm_default_t action = def; (void)action
diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h
index 7f7feffc68..a90a58e3a7 100644
--- a/xen/include/xsm/xsm.h
+++ b/xen/include/xsm/xsm.h
@@ -729,6 +729,12 @@ extern const unsigned char xsm_init_policy[];
 extern const unsigned int xsm_init_policy_size;
 #endif
 
+#ifdef CONFIG_XSM_SILO
+extern void silo_init(void);
+#else
+static inline void silo_init(void) {}
+#endif
+
 #else /* CONFIG_XSM */
 
 #include <xsm/dummy.h>
diff --git a/xen/xsm/Makefile b/xen/xsm/Makefile
index 3252c46e64..50e21303b3 100644
--- a/xen/xsm/Makefile
+++ b/xen/xsm/Makefile
@@ -1,5 +1,6 @@
 obj-y += xsm_core.o
 obj-$(CONFIG_XSM) += xsm_policy.o
 obj-$(CONFIG_XSM) += dummy.o
+obj-$(CONFIG_XSM_SILO) += silo.o
 
 subdir-$(CONFIG_FLASK) += flask
diff --git a/xen/xsm/silo.c b/xen/xsm/silo.c
new file mode 100644
index 0000000000..4850756a3d
--- /dev/null
+++ b/xen/xsm/silo.c
@@ -0,0 +1,108 @@
+/******************************************************************************
+ * xsm/silo.c
+ *
+ * SILO module for XSM (Xen Security Modules)
+ *
+ * Copyright (c) 2018 Citrix Systems Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+#define XSM_NO_WRAPPERS
+#include <xsm/dummy.h>
+
+/*
+ * Check if inter-domain communication is allowed.
+ * Return true when pass check.
+ */
+static bool silo_mode_dom_check(const struct domain *ldom,
+                                const struct domain *rdom)
+{
+    const struct domain *currd = current->domain;
+
+    return (is_control_domain(currd) || is_control_domain(ldom) ||
+            is_control_domain(rdom) || ldom == rdom);
+}
+
+static int silo_evtchn_unbound(struct domain *d1, struct evtchn *chn,
+                               domid_t id2)
+{
+    int rc = -EPERM;
+    struct domain *d2 = rcu_lock_domain_by_any_id(id2);
+
+    if ( d2 == NULL )
+        rc = -ESRCH;
+    else
+    {
+        if ( silo_mode_dom_check(d1, d2) )
+            rc = xsm_evtchn_unbound(d1, chn, id2);
+        rcu_unlock_domain(d2);
+    }
+
+    return rc;
+}
+
+static int silo_evtchn_interdomain(struct domain *d1, struct evtchn *chan1,
+                                   struct domain *d2, struct evtchn *chan2)
+{
+    if ( silo_mode_dom_check(d1, d2) )
+        return xsm_evtchn_interdomain(d1, chan1, d2, chan2);
+    return -EPERM;
+}
+
+static int silo_grant_mapref(struct domain *d1, struct domain *d2,
+                             uint32_t flags)
+{
+    if ( silo_mode_dom_check(d1, d2) )
+        return xsm_grant_mapref(d1, d2, flags);
+    return -EPERM;
+}
+
+static int silo_grant_transfer(struct domain *d1, struct domain *d2)
+{
+    if ( silo_mode_dom_check(d1, d2) )
+        return xsm_grant_transfer(d1, d2);
+    return -EPERM;
+}
+
+static int silo_grant_copy(struct domain *d1, struct domain *d2)
+{
+    if ( silo_mode_dom_check(d1, d2) )
+        return xsm_grant_copy(d1, d2);
+    return -EPERM;
+}
+
+static struct xsm_operations silo_xsm_ops = {
+    .evtchn_unbound = silo_evtchn_unbound,
+    .evtchn_interdomain = silo_evtchn_interdomain,
+    .grant_mapref = silo_grant_mapref,
+    .grant_transfer = silo_grant_transfer,
+    .grant_copy = silo_grant_copy,
+};
+
+void __init silo_init(void)
+{
+    printk("Initialising XSM SILO mode\n");
+
+    if ( register_xsm(&silo_xsm_ops) )
+        panic("SILO: Unable to register with XSM\n");
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/xsm/xsm_core.c b/xen/xsm/xsm_core.c
index e78f7d8ca2..91ef8a70b7 100644
--- a/xen/xsm/xsm_core.c
+++ b/xen/xsm/xsm_core.c
@@ -30,11 +30,14 @@ struct xsm_operations *xsm_ops;
 enum xsm_bootparam {
     XSM_BOOTPARAM_DUMMY,
     XSM_BOOTPARAM_FLASK,
+    XSM_BOOTPARAM_SILO,
 };
 
 static enum xsm_bootparam __initdata xsm_bootparam =
 #ifdef CONFIG_XSM_FLASK_DEFAULT
     XSM_BOOTPARAM_FLASK;
+#elif CONFIG_XSM_SILO_DEFAULT
+    XSM_BOOTPARAM_SILO;
 #else
     XSM_BOOTPARAM_DUMMY;
 #endif
@@ -48,6 +51,10 @@ static int __init parse_xsm_param(const char *s)
 #ifdef CONFIG_XSM_FLASK
     else if ( !strcmp(s, "flask") )
         xsm_bootparam = XSM_BOOTPARAM_FLASK;
+#endif
+#ifdef CONFIG_XSM_SILO
+    else if ( !strcmp(s, "silo") )
+        xsm_bootparam = XSM_BOOTPARAM_SILO;
 #endif
     else
         rc = -EINVAL;
@@ -92,6 +99,10 @@ static int __init xsm_core_init(const void *policy_buffer, size_t policy_size)
         flask_init(policy_buffer, policy_size);
         break;
 
+    case XSM_BOOTPARAM_SILO:
+        silo_init();
+        break;
+
     default:
         ASSERT_UNREACHABLE();
         break;
-- 
2.17.1
xsa295/4.10-15.patch (application/octet-stream, 3.5 KB)
From a6024d51e44c381d2403a9ed71b14dbcc2c70d26 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:25 +0100
Subject: [PATCH v2 4.10 15/20] xen/arm: Turn on SILO mode by default on Arm

On Arm, exclusive load-store atomics should only be used between trusted
thread. As not all the guests are trusted, it may be possible to DoS Xen
when updating shared memory with guest atomically.

Recent patches introduced new helpers to update shared memory with guest
atomically. Those helpers relies on a memory region to be be shared with
Xen and a single guest.

At the moment, nothing prevent a guest sharing a page with Xen and as
well with another guest (e.g via grant table).

For the scope of the XSA, the quickest way is to deny communications
between unprivileged guest. So this patch is enabling and using SILO
mode by default on Arm.

Users wanted finer graine policy could wrote their own Flask policy.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Acked-by: Jan Beulich <[email protected]>
---
 xen/arch/arm/setup.c  | 8 ++++++--
 xen/common/Kconfig    | 3 ++-
 xen/include/xsm/xsm.h | 5 +++++
 xen/xsm/xsm_core.c    | 2 +-
 4 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index 032a6a882d..8372cd26f6 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -37,6 +37,7 @@
 #include <xen/vmap.h>
 #include <xen/libfdt/libfdt.h>
 #include <xen/acpi.h>
+#include <xen/warning.h>
 #include <asm/alternative.h>
 #include <asm/page.h>
 #include <asm/current.h>
@@ -800,8 +801,11 @@ void __init start_xen(unsigned long boot_phys_offset,
 
     tasklet_subsys_init();
 
-
-    xsm_dt_init();
+    if ( xsm_dt_init() != 1 )
+        warning_add("WARNING: SILO mode is not enabled.\n"
+                    "It has implications on the security of the system,\n"
+                    "unless the communications have been forbidden between\n"
+                    "untrusted domains.\n");
 
     init_maintenance_interrupt();
     init_timer_interrupt();
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index 43810fc026..97229c2f71 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -90,7 +90,7 @@ config XENOPROF
 
 config XSM
 	bool "Xen Security Modules support"
-	default n
+	default ARM
 	---help---
 	  Enables the security framework known as Xen Security Modules which
 	  allows administrators fine-grained control over a Xen domain and
@@ -155,6 +155,7 @@ config XSM_SILO
 choice
 	prompt "Default XSM implementation"
 	depends on XSM
+	default XSM_SILO_DEFAULT if XSM_SILO && ARM
 	default XSM_FLASK_DEFAULT if XSM_FLASK
 	default XSM_SILO_DEFAULT if XSM_SILO
 	default XSM_DUMMY_DEFAULT
diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h
index a90a58e3a7..0845cb06ae 100644
--- a/xen/include/xsm/xsm.h
+++ b/xen/include/xsm/xsm.h
@@ -706,6 +706,11 @@ extern int xsm_multiboot_policy_init(unsigned long *module_map,
 #endif
 
 #ifdef CONFIG_HAS_DEVICE_TREE
+/*
+ * Initialize XSM
+ *
+ * On success, return 1 if using SILO mode else 0.
+ */
 extern int xsm_dt_init(void);
 extern int xsm_dt_policy_init(void **policy_buffer, size_t *policy_size);
 extern bool has_xsm_magic(paddr_t);
diff --git a/xen/xsm/xsm_core.c b/xen/xsm/xsm_core.c
index 91ef8a70b7..2a2100929d 100644
--- a/xen/xsm/xsm_core.c
+++ b/xen/xsm/xsm_core.c
@@ -164,7 +164,7 @@ int __init xsm_dt_init(void)
 
     xfree(policy_buffer);
 
-    return ret;
+    return ret ?: (xsm_bootparam == XSM_BOOTPARAM_SILO);
 }
 
 /**
-- 
2.17.1
xsa295/4.10-16.patch (application/octet-stream, 9.6 KB)
From 356b8c999358608ef8a16b1186170a8d805d7bec Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:26 +0100
Subject: [PATCH v2 4.10 16/20] xen/bitops: Provide helpers to safely modify
 guest memory atomically

On Arm, exclusive load-store atomics should only be used between trusted
thread. As not all the guests are trusted, it may be possible to DoS Xen
when updating shared memory with guest atomically.

This patch adds a new set of helper that will update the guest memory
safely. For x86, it is already possible to use the current helpers
safely. So just wrap them.

For Arm, we will first attempt to update the guest memory with the loop
bounded by a maximum number of iterations. If it fails, we will pause the
domain and try again.

Note that this heuristics assumes that a page can only be shared between
Xen and one domain. Not Xen and multiple domain.

The maximum number of iterations is based on how many times a simple
load-store atomic operation can be executed in 1uS. The maximum value is
per-CPU to cater big.LITTLE and calculated when the CPU is booting. The
heuristic was randomly chosen and can be modified if impact too much
good-behaving guest.

Note, while test_bit does not requires to use atomic operation, a
wrapper for test_bit was added for completeness. In this case, the
domain stays constified to avoid major rework in the caller for the
time-being.

This is part of XSA-295.

Signed-of-by: Julien Grall <[email protected]>
Acked-by: Jan Beulich <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/Makefile               |  1 +
 xen/arch/arm/guest_atomics.c        | 91 +++++++++++++++++++++++++++++
 xen/include/asm-arm/guest_atomics.h | 76 ++++++++++++++++++++++++
 xen/include/asm-x86/guest_atomics.h | 30 ++++++++++
 4 files changed, 198 insertions(+)
 create mode 100644 xen/arch/arm/guest_atomics.c
 create mode 100644 xen/include/asm-arm/guest_atomics.h
 create mode 100644 xen/include/asm-x86/guest_atomics.h

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 30a2a6500a..6229e5bfc5 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_HAS_GICV3) += gic-v3.o
 obj-$(CONFIG_HAS_ITS) += gic-v3-its.o
 obj-$(CONFIG_HAS_ITS) += gic-v3-lpi.o
 obj-y += guestcopy.o
+obj-y += guest_atomics.o
 obj-y += guest_walk.o
 obj-y += hvm.o
 obj-y += io.o
diff --git a/xen/arch/arm/guest_atomics.c b/xen/arch/arm/guest_atomics.c
new file mode 100644
index 0000000000..1b78a062f0
--- /dev/null
+++ b/xen/arch/arm/guest_atomics.c
@@ -0,0 +1,91 @@
+/*
+ * arch/arm/guest_atomics.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <xen/cpu.h>
+
+#include <asm/guest_atomics.h>
+
+DEFINE_PER_CPU_READ_MOSTLY(unsigned int, guest_safe_atomic_max);
+
+/*
+ * Heuristic to find a safe upper-limit for load-store exclusive
+ * operations on memory shared with guest.
+ *
+ * At the moment, we calculate the number of iterations of a simple
+ * load-store atomic loop in 1uS.
+ */
+static void calibrate_safe_atomic(void)
+{
+    s_time_t deadline = NOW() + MICROSECS(1);
+    unsigned int counter = 0;
+    unsigned long mem = 0;
+
+    do
+    {
+        unsigned long res, tmp;
+
+#ifdef CONFIG_ARM_32
+        asm volatile (" ldrex   %2, %1\n"
+                      " add     %2, %2, #1\n"
+                      " strex   %0, %2, %1\n"
+                      : "=&r" (res), "+Q" (mem), "=&r" (tmp));
+#else
+        asm volatile (" ldxr    %w2, %1\n"
+                      " add     %w2, %w2, #1\n"
+                      " stxr    %w0, %w2, %1\n"
+                      : "=&r" (res), "+Q" (mem), "=&r" (tmp));
+#endif
+        counter++;
+    } while (NOW() < deadline);
+
+    this_cpu(guest_safe_atomic_max) = counter;
+
+    printk(XENLOG_DEBUG
+           "CPU%u: Guest atomics will try %u times before pausing the domain\n",
+           smp_processor_id(), counter);
+}
+
+static int cpu_guest_safe_atomic_callback(struct notifier_block *nfb,
+                                          unsigned long action,
+                                          void *hcpu)
+{
+    if ( action == CPU_STARTING )
+        calibrate_safe_atomic();
+
+    return NOTIFY_DONE;
+}
+
+static struct notifier_block cpu_guest_safe_atomic_nfb = {
+    .notifier_call = cpu_guest_safe_atomic_callback,
+};
+
+static int __init guest_safe_atomic_init(void)
+{
+    register_cpu_notifier(&cpu_guest_safe_atomic_nfb);
+
+    calibrate_safe_atomic();
+
+    return 0;
+}
+presmp_initcall(guest_safe_atomic_init);
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-arm/guest_atomics.h b/xen/include/asm-arm/guest_atomics.h
new file mode 100644
index 0000000000..4f127fda41
--- /dev/null
+++ b/xen/include/asm-arm/guest_atomics.h
@@ -0,0 +1,76 @@
+#ifndef _ARM_GUEST_ATOMICS_H
+#define _ARM_GUEST_ATOMICS_H
+
+#include <xen/bitops.h>
+#include <xen/sched.h>
+
+/*
+ * The guest atomics helpers shares the same logic. We first try to use
+ * the *_timeout version of the operation. If it didn't timeout, then we
+ * successfully updated the memory. Nothing else to do.
+ *
+ * If it did timeout, then it means we didn't manage to update the
+ * memory. This is possibly because the guest is misbehaving (i.e tight
+ * store loop) but can also happen for other reasons (i.e nested Xen).
+ * In that case pause the domain and retry the operation, this time
+ * without a timeout.
+ *
+ * Note, those helpers rely on other part of the code to prevent sharing
+ * a page between Xen and multiple domain.
+ */
+
+DECLARE_PER_CPU(unsigned int, guest_safe_atomic_max);
+
+#define guest_bitop(name)                                                   \
+static inline void guest_##name(struct domain *d, int nr, volatile void *p) \
+{                                                                           \
+    if ( name##_timeout(nr, p, this_cpu(guest_safe_atomic_max)) )           \
+        return;                                                             \
+                                                                            \
+    domain_pause_nosync(d);                                                 \
+    name(nr, p);                                                            \
+    domain_unpause(d);                                                      \
+}
+
+#define guest_testop(name)                                                  \
+static inline int guest_##name(struct domain *d, int nr, volatile void *p)  \
+{                                                                           \
+    bool succeed;                                                           \
+    int oldbit;                                                             \
+                                                                            \
+    succeed = name##_timeout(nr, p, &oldbit,                                \
+                             this_cpu(guest_safe_atomic_max));              \
+    if ( succeed )                                                          \
+        return oldbit;                                                      \
+                                                                            \
+    domain_pause_nosync(d);                                                 \
+    oldbit = name(nr, p);                                                   \
+    domain_unpause(d);                                                      \
+                                                                            \
+    return oldbit;                                                          \
+}
+
+guest_bitop(set_bit)
+guest_bitop(clear_bit)
+guest_bitop(change_bit)
+
+#undef guest_bitop
+
+/* test_bit does not use load-store atomic operations */
+#define guest_test_bit(d, nr, p) ((void)(d), test_bit(nr, p))
+
+guest_testop(test_and_set_bit)
+guest_testop(test_and_clear_bit)
+guest_testop(test_and_change_bit)
+
+#undef guest_testop
+
+#endif /* _ARM_GUEST_ATOMICS_H */
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-x86/guest_atomics.h b/xen/include/asm-x86/guest_atomics.h
new file mode 100644
index 0000000000..0c71d2d278
--- /dev/null
+++ b/xen/include/asm-x86/guest_atomics.h
@@ -0,0 +1,30 @@
+#ifndef _X86_GUEST_ATOMICS_H
+#define _X86_GUEST_ATOMICS_H
+
+#include <xen/bitops.h>
+
+/*
+ * It is safe to use the atomics helpers on x86 on memory shared with
+ * the guests.
+ */
+#define guest_set_bit(d, nr, p)     ((void)(d), set_bit(nr, p))
+#define guest_clear_bit(d, nr, p)   ((void)(d), clear_bit(nr, p))
+#define guest_change_bit(d, nr, p)  ((void)(d), change_bit(nr, p))
+#define guest_test_bit(d, nr, p)    ((void)(d), test_bit(nr, p))
+
+#define guest_test_and_set_bit(d, nr, p)    \
+    ((void)(d), test_and_set_bit(nr, p))
+#define guest_test_and_clear_bit(d, nr, p)  \
+    ((void)(d), test_and_clear_bit(nr, p))
+#define guest_test_and_change_bit(d, nr, p) \
+    ((void)(d), test_and_change_bit(nr, p))
+
+#endif /* _X86_GUEST_ATOMICS_H */
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.17.1
xsa295/4.10-17.patch (application/octet-stream, 3.4 KB)
From abef08f87d42c4550d4d38e0144b44c163c0a55d Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:27 +0100
Subject: [PATCH v2 4.10 17/20] xen/cmpxchg: Provide helper to safely modify
 guest memory atomically

On Arm, exclusive load-store atomics should only be used between trusted
thread. As not all the guests are trusted, it may be possible to DoS Xen
when updating shared memory with guest atomically.

This patch adds a new helper that will update the guest memory safely.
For x86, it is already possible to use the current helper safely. So
just wrap it.

For Arm, we will first attempt to update the guest memory with the
loop bounded by a maximum number of iterations. If it fails, we will
pause the domain and try again.

Note that this heuristics assumes that a page can only
be shared between Xen and one domain. Not Xen and multiple domain.

The maximum number of iterations is based on how many times atomic_inc()
can be executed in 1uS. The maximum value is per-CPU to cater big.LITTLE
and calculated when the CPU is booting.

The maximum number of iterations is based on how many times a simple
load-store atomic operation can be executed in 1uS. The maximum
value is per-CPU to cater big.LITTLE and calculated when the CPU is
booting. The heuristic was randomly chosen and can be modified if
impact too much good-behaving guest.

This is part of XSA-295.

Signed-of-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Acked-by: Jan Beulich <[email protected]>
---
 xen/include/asm-arm/guest_atomics.h | 25 +++++++++++++++++++++++++
 xen/include/asm-x86/guest_atomics.h |  2 ++
 2 files changed, 27 insertions(+)

diff --git a/xen/include/asm-arm/guest_atomics.h b/xen/include/asm-arm/guest_atomics.h
index 4f127fda41..61925d313d 100644
--- a/xen/include/asm-arm/guest_atomics.h
+++ b/xen/include/asm-arm/guest_atomics.h
@@ -65,6 +65,31 @@ guest_testop(test_and_change_bit)
 
 #undef guest_testop
 
+static inline unsigned long __guest_cmpxchg(struct domain *d,
+                                            volatile void *ptr,
+                                            unsigned long old,
+                                            unsigned long new,
+                                            unsigned int size)
+{
+    unsigned long oldval = old;
+
+    if ( __cmpxchg_mb_timeout(ptr, &oldval, new, size,
+                              this_cpu(guest_safe_atomic_max)) )
+        return oldval;
+
+    domain_pause_nosync(d);
+    oldval = __cmpxchg_mb(ptr, old, new, size);
+    domain_unpause(d);
+
+    return oldval;
+}
+
+#define guest_cmpxchg(d, ptr, o, n)                         \
+    ((__typeof__(*(ptr)))__guest_cmpxchg(d, ptr,            \
+                                         (unsigned long)(o),\
+                                         (unsigned long)(n),\
+                                         sizeof (*(ptr))))
+
 #endif /* _ARM_GUEST_ATOMICS_H */
 /*
  * Local variables:
diff --git a/xen/include/asm-x86/guest_atomics.h b/xen/include/asm-x86/guest_atomics.h
index 0c71d2d278..029417c8ff 100644
--- a/xen/include/asm-x86/guest_atomics.h
+++ b/xen/include/asm-x86/guest_atomics.h
@@ -19,6 +19,8 @@
 #define guest_test_and_change_bit(d, nr, p) \
     ((void)(d), test_and_change_bit(nr, p))
 
+#define guest_cmpxchg(d, ptr, o, n) ((void)(d), cmpxchg(ptr, o, n))
+
 #endif /* _X86_GUEST_ATOMICS_H */
 /*
  * Local variables:
-- 
2.17.1
xsa295/4.10-18.patch (application/octet-stream, 22.4 KB)
From 23693f6ededa31c0ad5d530a0dda42d833c7672a Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:28 +0100
Subject: [PATCH v2 4.10 18/20] xen: Use guest atomics helpers when modifying
 atomically guest memory

On Arm, exclusive load-store atomics should only be used between trusted
thread. As not all the guests are trusted, it may be possible to DoS Xen
when updating shared memory with guest atomically.

This patch replaces all the atomics operations on shared memory with
a guest by the new guest atomics helpers. The x86 code was not audited
to know where guest atomics helpers could be used. I will leave that
to the x86 folks.

Note that some rework was required in order to plumb use the new guest
atomics in event channel and grant-table.

Because guest_test_bit is ignoring the parameter "d" for now, it
means there a lot of places do not need to drop the const. We may want
to revisit this in the future if the parameter "d" becomes necessary.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/domain.c             |  3 +-
 xen/arch/arm/mm.c                 |  6 ++--
 xen/common/event_2l.c             | 26 ++++++++------
 xen/common/event_fifo.c           | 44 ++++++++++++-----------
 xen/common/grant_table.c          | 59 +++++++++++++++++--------------
 xen/include/asm-arm/grant_table.h |  2 +-
 xen/include/asm-x86/grant_table.h |  3 +-
 7 files changed, 79 insertions(+), 64 deletions(-)

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index a74ff1c07c..0f220d4af2 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -26,6 +26,7 @@
 #include <asm/event.h>
 #include <asm/gic.h>
 #include <asm/guest_access.h>
+#include <asm/guest_atomics.h>
 #include <asm/irq.h>
 #include <asm/p2m.h>
 #include <asm/platform.h>
@@ -945,7 +946,7 @@ void arch_dump_vcpu_info(struct vcpu *v)
 
 void vcpu_mark_events_pending(struct vcpu *v)
 {
-    int already_pending = test_and_set_bit(
+    bool already_pending = guest_test_and_set_bit(v->domain,
         0, (unsigned long *)&vcpu_info(v, evtchn_upcall_pending));
 
     if ( already_pending )
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 3c328e2df5..097a6424a4 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -40,6 +40,8 @@
 #include <xen/pfn.h>
 #include <xen/sizes.h>
 #include <xen/libfdt/libfdt.h>
+
+#include <asm/guest_atomics.h>
 #include <asm/setup.h>
 
 struct domain *dom_xen, *dom_io, *dom_cow;
@@ -1401,7 +1403,7 @@ void put_page_type(struct page_info *page)
     return;
 }
 
-void gnttab_clear_flag(unsigned long nr, uint16_t *addr)
+void gnttab_clear_flag(struct domain *d, unsigned long nr, uint16_t *addr)
 {
     /*
      * Note that this cannot be clear_bit(), as the access must be
@@ -1411,7 +1413,7 @@ void gnttab_clear_flag(unsigned long nr, uint16_t *addr)
 
     do {
         old = *addr;
-    } while (cmpxchg(addr, old, old & mask) != old);
+    } while (guest_cmpxchg(d, addr, old, old & mask) != old);
 }
 
 void gnttab_mark_dirty(struct domain *d, unsigned long l)
diff --git a/xen/common/event_2l.c b/xen/common/event_2l.c
index 8ca90899ab..e1dbb860f4 100644
--- a/xen/common/event_2l.c
+++ b/xen/common/event_2l.c
@@ -13,6 +13,8 @@
 #include <xen/sched.h>
 #include <xen/event.h>
 
+#include <asm/guest_atomics.h>
+
 static void evtchn_2l_set_pending(struct vcpu *v, struct evtchn *evtchn)
 {
     struct domain *d = v->domain;
@@ -25,12 +27,12 @@ static void evtchn_2l_set_pending(struct vcpu *v, struct evtchn *evtchn)
      * others may require explicit memory barriers.
      */
 
-    if ( test_and_set_bit(port, &shared_info(d, evtchn_pending)) )
+    if ( guest_test_and_set_bit(d, port, &shared_info(d, evtchn_pending)) )
         return;
 
-    if ( !test_bit        (port, &shared_info(d, evtchn_mask)) &&
-         !test_and_set_bit(port / BITS_PER_EVTCHN_WORD(d),
-                           &vcpu_info(v, evtchn_pending_sel)) )
+    if ( !guest_test_bit(d, port, &shared_info(d, evtchn_mask)) &&
+         !guest_test_and_set_bit(d, port / BITS_PER_EVTCHN_WORD(d),
+                                 &vcpu_info(v, evtchn_pending_sel)) )
     {
         vcpu_mark_events_pending(v);
     }
@@ -40,7 +42,7 @@ static void evtchn_2l_set_pending(struct vcpu *v, struct evtchn *evtchn)
 
 static void evtchn_2l_clear_pending(struct domain *d, struct evtchn *evtchn)
 {
-    clear_bit(evtchn->port, &shared_info(d, evtchn_pending));
+    guest_clear_bit(d, evtchn->port, &shared_info(d, evtchn_pending));
 }
 
 static void evtchn_2l_unmask(struct domain *d, struct evtchn *evtchn)
@@ -52,10 +54,10 @@ static void evtchn_2l_unmask(struct domain *d, struct evtchn *evtchn)
      * These operations must happen in strict order. Based on
      * evtchn_2l_set_pending() above.
      */
-    if ( test_and_clear_bit(port, &shared_info(d, evtchn_mask)) &&
-         test_bit          (port, &shared_info(d, evtchn_pending)) &&
-         !test_and_set_bit (port / BITS_PER_EVTCHN_WORD(d),
-                            &vcpu_info(v, evtchn_pending_sel)) )
+    if ( guest_test_and_clear_bit(d, port, &shared_info(d, evtchn_mask)) &&
+         guest_test_bit(d, port, &shared_info(d, evtchn_pending)) &&
+         !guest_test_and_set_bit(d, port / BITS_PER_EVTCHN_WORD(d),
+                                 &vcpu_info(v, evtchn_pending_sel)) )
     {
         vcpu_mark_events_pending(v);
     }
@@ -66,7 +68,8 @@ static bool evtchn_2l_is_pending(const struct domain *d, evtchn_port_t port)
     unsigned int max_ports = BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d);
 
     ASSERT(port < max_ports);
-    return port < max_ports && test_bit(port, &shared_info(d, evtchn_pending));
+    return (port < max_ports &&
+            guest_test_bit(d, port, &shared_info(d, evtchn_pending)));
 }
 
 static bool evtchn_2l_is_masked(const struct domain *d, evtchn_port_t port)
@@ -74,7 +77,8 @@ static bool evtchn_2l_is_masked(const struct domain *d, evtchn_port_t port)
     unsigned int max_ports = BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d);
 
     ASSERT(port < max_ports);
-    return port >= max_ports || test_bit(port, &shared_info(d, evtchn_mask));
+    return (port >= max_ports ||
+            guest_test_bit(d, port, &shared_info(d, evtchn_mask)));
 }
 
 static void evtchn_2l_print_state(struct domain *d,
diff --git a/xen/common/event_fifo.c b/xen/common/event_fifo.c
index c49f446754..3f4c835518 100644
--- a/xen/common/event_fifo.c
+++ b/xen/common/event_fifo.c
@@ -17,6 +17,8 @@
 #include <xen/mm.h>
 #include <xen/domain_page.h>
 
+#include <asm/guest_atomics.h>
+
 #include <public/event_channel.h>
 
 static inline event_word_t *evtchn_fifo_word_from_port(const struct domain *d,
@@ -50,7 +52,7 @@ static void evtchn_fifo_init(struct domain *d, struct evtchn *evtchn)
      * on the wrong VCPU or with an unexpected priority.
      */
     word = evtchn_fifo_word_from_port(d, evtchn->port);
-    if ( word && test_bit(EVTCHN_FIFO_LINKED, word) )
+    if ( word && guest_test_bit(d, EVTCHN_FIFO_LINKED, word) )
         gdprintk(XENLOG_WARNING, "domain %d, port %d already on a queue\n",
                  d->domain_id, evtchn->port);
 }
@@ -115,7 +117,7 @@ static int try_set_link(event_word_t *word, event_word_t *w, uint32_t link)
  * We block unmasking by the guest by marking the tail word as BUSY,
  * therefore, the cmpxchg() may fail at most 4 times.
  */
-static bool_t evtchn_fifo_set_link(const struct domain *d, event_word_t *word,
+static bool_t evtchn_fifo_set_link(struct domain *d, event_word_t *word,
                                    uint32_t link)
 {
     event_word_t w;
@@ -129,7 +131,7 @@ static bool_t evtchn_fifo_set_link(const struct domain *d, event_word_t *word,
         return ret;
 
     /* Lock the word to prevent guest unmasking. */
-    set_bit(EVTCHN_FIFO_BUSY, word);
+    guest_set_bit(d, EVTCHN_FIFO_BUSY, word);
 
     w = read_atomic(word);
 
@@ -139,13 +141,13 @@ static bool_t evtchn_fifo_set_link(const struct domain *d, event_word_t *word,
         if ( ret >= 0 )
         {
             if ( ret == 0 )
-                clear_bit(EVTCHN_FIFO_BUSY, word);
+                guest_clear_bit(d, EVTCHN_FIFO_BUSY, word);
             return ret;
         }
     }
     gdprintk(XENLOG_WARNING, "domain %d, port %d not linked\n",
              d->domain_id, link);
-    clear_bit(EVTCHN_FIFO_BUSY, word);
+    guest_clear_bit(d, EVTCHN_FIFO_BUSY, word);
     return 1;
 }
 
@@ -170,13 +172,13 @@ static void evtchn_fifo_set_pending(struct vcpu *v, struct evtchn *evtchn)
         return;
     }
 
-    was_pending = test_and_set_bit(EVTCHN_FIFO_PENDING, word);
+    was_pending = guest_test_and_set_bit(d, EVTCHN_FIFO_PENDING, word);
 
     /*
      * Link the event if it unmasked and not already linked.
      */
-    if ( !test_bit(EVTCHN_FIFO_MASKED, word)
-         && !test_bit(EVTCHN_FIFO_LINKED, word) )
+    if ( !guest_test_bit(d, EVTCHN_FIFO_MASKED, word) &&
+         !guest_test_bit(d, EVTCHN_FIFO_LINKED, word) )
     {
         struct evtchn_fifo_queue *q, *old_q;
         event_word_t *tail_word;
@@ -205,7 +207,7 @@ static void evtchn_fifo_set_pending(struct vcpu *v, struct evtchn *evtchn)
         if ( !old_q )
             goto done;
 
-        if ( test_and_set_bit(EVTCHN_FIFO_LINKED, word) )
+        if ( guest_test_and_set_bit(d, EVTCHN_FIFO_LINKED, word) )
         {
             spin_unlock_irqrestore(&old_q->lock, flags);
             goto done;
@@ -251,8 +253,8 @@ static void evtchn_fifo_set_pending(struct vcpu *v, struct evtchn *evtchn)
         spin_unlock_irqrestore(&q->lock, flags);
 
         if ( !linked
-             && !test_and_set_bit(q->priority,
-                                  &v->evtchn_fifo->control_block->ready) )
+             && !guest_test_and_set_bit(d, q->priority,
+                                        &v->evtchn_fifo->control_block->ready) )
             vcpu_mark_events_pending(v);
     }
  done:
@@ -274,7 +276,7 @@ static void evtchn_fifo_clear_pending(struct domain *d, struct evtchn *evtchn)
      * No need to unlink as the guest will unlink and ignore
      * non-pending events.
      */
-    clear_bit(EVTCHN_FIFO_PENDING, word);
+    guest_clear_bit(d, EVTCHN_FIFO_PENDING, word);
 }
 
 static void evtchn_fifo_unmask(struct domain *d, struct evtchn *evtchn)
@@ -286,10 +288,10 @@ static void evtchn_fifo_unmask(struct domain *d, struct evtchn *evtchn)
     if ( unlikely(!word) )
         return;
 
-    clear_bit(EVTCHN_FIFO_MASKED, word);
+    guest_clear_bit(d, EVTCHN_FIFO_MASKED, word);
 
     /* Relink if pending. */
-    if ( test_bit(EVTCHN_FIFO_PENDING, word) )
+    if ( guest_test_bit(d, EVTCHN_FIFO_PENDING, word) )
         evtchn_fifo_set_pending(v, evtchn);
 }
 
@@ -297,21 +299,21 @@ static bool evtchn_fifo_is_pending(const struct domain *d, evtchn_port_t port)
 {
     const event_word_t *word = evtchn_fifo_word_from_port(d, port);
 
-    return word && test_bit(EVTCHN_FIFO_PENDING, word);
+    return word && guest_test_bit(d, EVTCHN_FIFO_PENDING, word);
 }
 
 static bool_t evtchn_fifo_is_masked(const struct domain *d, evtchn_port_t port)
 {
     const event_word_t *word = evtchn_fifo_word_from_port(d, port);
 
-    return !word || test_bit(EVTCHN_FIFO_MASKED, word);
+    return !word || guest_test_bit(d, EVTCHN_FIFO_MASKED, word);
 }
 
 static bool_t evtchn_fifo_is_busy(const struct domain *d, evtchn_port_t port)
 {
     const event_word_t *word = evtchn_fifo_word_from_port(d, port);
 
-    return word && test_bit(EVTCHN_FIFO_LINKED, word);
+    return word && guest_test_bit(d, EVTCHN_FIFO_LINKED, word);
 }
 
 static int evtchn_fifo_set_priority(struct domain *d, struct evtchn *evtchn,
@@ -338,11 +340,11 @@ static void evtchn_fifo_print_state(struct domain *d,
     word = evtchn_fifo_word_from_port(d, evtchn->port);
     if ( !word )
         printk("?     ");
-    else if ( test_bit(EVTCHN_FIFO_LINKED, word) )
-        printk("%c %-4u", test_bit(EVTCHN_FIFO_BUSY, word) ? 'B' : ' ',
+    else if ( guest_test_bit(d, EVTCHN_FIFO_LINKED, word) )
+        printk("%c %-4u", guest_test_bit(d, EVTCHN_FIFO_BUSY, word) ? 'B' : ' ',
                *word & EVTCHN_FIFO_LINK_MASK);
     else
-        printk("%c -   ", test_bit(EVTCHN_FIFO_BUSY, word) ? 'B' : ' ');
+        printk("%c -   ", guest_test_bit(d, EVTCHN_FIFO_BUSY, word) ? 'B' : ' ');
 }
 
 static const struct evtchn_port_ops evtchn_port_ops_fifo =
@@ -494,7 +496,7 @@ static void setup_ports(struct domain *d)
 
         evtchn = evtchn_from_port(d, port);
 
-        if ( test_bit(port, &shared_info(d, evtchn_pending)) )
+        if ( guest_test_bit(d, port, &shared_info(d, evtchn_pending)) )
             evtchn->pending = 1;
 
         evtchn_fifo_set_priority(d, evtchn, EVTCHN_FIFO_PRIORITY_DEFAULT);
diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index 0327335585..da7b644702 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -39,6 +39,7 @@
 #include <xen/vmap.h>
 #include <xsm/xsm.h>
 #include <asm/flushtlb.h>
+#include <asm/guest_atomics.h>
 
 /* Per-domain grant information. */
 struct grant_table {
@@ -653,6 +654,7 @@ static unsigned int nr_grant_entries(struct grant_table *gt)
 }
 
 static int _set_status_v1(const grant_entry_header_t *shah,
+                          struct domain *rd,
                           struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
@@ -708,8 +710,8 @@ static int _set_status_v1(const grant_entry_header_t *shah,
                          "Attempt to write-pin a r/o grant entry\n");
         }
 
-        prev_scombo.word = cmpxchg((u32 *)shah,
-                                   scombo.word, new_scombo.word);
+        prev_scombo.word = guest_cmpxchg(rd, (u32 *)shah,
+                                         scombo.word, new_scombo.word);
         if ( likely(prev_scombo.word == scombo.word) )
             break;
 
@@ -726,6 +728,7 @@ done:
 
 static int _set_status_v2(const grant_entry_header_t *shah,
                           grant_status_t *status,
+                          struct domain *rd,
                           struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
@@ -788,8 +791,8 @@ static int _set_status_v2(const grant_entry_header_t *shah,
              (id != ldomid) ||
              (!readonly && (flags & GTF_readonly)) )
         {
-            gnttab_clear_flag(_GTF_writing, status);
-            gnttab_clear_flag(_GTF_reading, status);
+            gnttab_clear_flag(rd, _GTF_writing, status);
+            gnttab_clear_flag(rd, _GTF_reading, status);
             PIN_FAIL(done, GNTST_general_error,
                      "Unstable flags (%x) or dom (%d); expected d%d (r/w: %d)\n",
                      flags, id, ldomid, !readonly);
@@ -799,7 +802,7 @@ static int _set_status_v2(const grant_entry_header_t *shah,
     {
         if ( unlikely(flags & GTF_readonly) )
         {
-            gnttab_clear_flag(_GTF_writing, status);
+            gnttab_clear_flag(rd, _GTF_writing, status);
             PIN_FAIL(done, GNTST_general_error,
                      "Unstable grant readonly flag\n");
         }
@@ -812,6 +815,7 @@ done:
 
 static int _set_status(const grant_entry_header_t *shah,
                        grant_status_t *status,
+                       struct domain *rd,
                        unsigned rgt_version,
                        struct active_grant_entry *act,
                        int readonly,
@@ -820,9 +824,9 @@ static int _set_status(const grant_entry_header_t *shah,
 {
 
     if ( rgt_version == 1 )
-        return _set_status_v1(shah, act, readonly, mapflag, ldomid);
+        return _set_status_v1(shah, rd, act, readonly, mapflag, ldomid);
     else
-        return _set_status_v2(shah, status, act, readonly, mapflag, ldomid);
+        return _set_status_v2(shah, status, rd, act, readonly, mapflag, ldomid);
 }
 
 static struct active_grant_entry *grant_map_exists(const struct domain *ld,
@@ -993,7 +997,7 @@ map_grant_ref(
          (!(op->flags & GNTMAP_readonly) &&
           !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask))) )
     {
-        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+        if ( (rc = _set_status(shah, status, rd, rgt->gt_version, act,
                                op->flags & GNTMAP_readonly, 1,
                                ld->domain_id) != GNTST_okay) )
             goto act_release_out;
@@ -1216,10 +1220,10 @@ map_grant_ref(
  unlock_out_clear:
     if ( !(op->flags & GNTMAP_readonly) &&
          !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) )
-        gnttab_clear_flag(_GTF_writing, status);
+        gnttab_clear_flag(rd, _GTF_writing, status);
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 
  act_release_out:
     active_entry_release(act);
@@ -1502,10 +1506,10 @@ unmap_common_complete(struct gnttab_unmap_common *op)
 
     if ( ((act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0) &&
          !(op->done & GNTMAP_readonly) )
-        gnttab_clear_flag(_GTF_writing, status);
+        gnttab_clear_flag(rd, _GTF_writing, status);
 
     if ( act->pin == 0 )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 
     active_entry_release(act);
     grant_read_unlock(rgt);
@@ -2070,8 +2074,8 @@ gnttab_prepare_for_transfer(
         new_scombo = scombo;
         new_scombo.shorts.flags |= GTF_transfer_committed;
 
-        prev_scombo.word = cmpxchg((u32 *)&sha->flags,
-                                   scombo.word, new_scombo.word);
+        prev_scombo.word = guest_cmpxchg(rd, (u32 *)&sha->flags,
+                                         scombo.word, new_scombo.word);
         if ( likely(prev_scombo.word == scombo.word) )
             break;
 
@@ -2356,11 +2360,11 @@ release_grant_for_copy(
 
         act->pin -= GNTPIN_hstw_inc;
         if ( !(act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) )
-            gnttab_clear_flag(_GTF_writing, status);
+            gnttab_clear_flag(rd, _GTF_writing, status);
     }
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 
     active_entry_release(act);
     grant_read_unlock(rgt);
@@ -2382,14 +2386,15 @@ release_grant_for_copy(
    under the domain's grant table lock. */
 /* Only safe on transitive grants.  Even then, note that we don't
    attempt to drop any pin on the referent grant. */
-static void fixup_status_for_copy_pin(const struct active_grant_entry *act,
+static void fixup_status_for_copy_pin(struct domain *rd,
+                                      const struct active_grant_entry *act,
                                       uint16_t *status)
 {
     if ( !(act->pin & (GNTPIN_hstw_mask | GNTPIN_devw_mask)) )
-        gnttab_clear_flag(_GTF_writing, status);
+        gnttab_clear_flag(rd, _GTF_writing, status);
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 }
 
 /* Grab a frame number from a grant entry and update the flags and pin
@@ -2449,7 +2454,7 @@ acquire_grant_for_copy(
     {
         if ( (!old_pin || (!readonly &&
                            !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)))) &&
-             (rc = _set_status_v2(shah, status, act, readonly, 0,
+             (rc = _set_status_v2(shah, status, rd, act, readonly, 0,
                                   ldom)) != GNTST_okay )
             goto unlock_out;
 
@@ -2498,7 +2503,7 @@ acquire_grant_for_copy(
 
         if ( rc != GNTST_okay )
         {
-            fixup_status_for_copy_pin(act, status);
+            fixup_status_for_copy_pin(rd, act, status);
             rcu_unlock_domain(td);
             active_entry_release(act);
             grant_read_unlock(rgt);
@@ -2520,7 +2525,7 @@ acquire_grant_for_copy(
                           !act->is_sub_page)) )
         {
             release_grant_for_copy(td, trans_gref, readonly);
-            fixup_status_for_copy_pin(act, status);
+            fixup_status_for_copy_pin(rd, act, status);
             rcu_unlock_domain(td);
             active_entry_release(act);
             grant_read_unlock(rgt);
@@ -2549,7 +2554,7 @@ acquire_grant_for_copy(
     else if ( !old_pin ||
               (!readonly && !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask))) )
     {
-        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+        if ( (rc = _set_status(shah, status, rd, rgt->gt_version, act,
                                readonly, 0, ldom)) != GNTST_okay )
              goto unlock_out;
 
@@ -2637,10 +2642,10 @@ acquire_grant_for_copy(
  unlock_out_clear:
     if ( !(readonly) &&
          !(act->pin & (GNTPIN_hstw_mask | GNTPIN_devw_mask)) )
-        gnttab_clear_flag(_GTF_writing, status);
+        gnttab_clear_flag(rd, _GTF_writing, status);
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 
  unlock_out:
     active_entry_release(act);
@@ -3707,11 +3712,11 @@ gnttab_release_mappings(
             }
 
             if ( (act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0 )
-                gnttab_clear_flag(_GTF_writing, status);
+                gnttab_clear_flag(rd, _GTF_writing, status);
         }
 
         if ( act->pin == 0 )
-            gnttab_clear_flag(_GTF_reading, status);
+            gnttab_clear_flag(rd, _GTF_reading, status);
 
         active_entry_release(act);
         grant_read_unlock(rgt);
diff --git a/xen/include/asm-arm/grant_table.h b/xen/include/asm-arm/grant_table.h
index 619721f121..63ba0ef045 100644
--- a/xen/include/asm-arm/grant_table.h
+++ b/xen/include/asm-arm/grant_table.h
@@ -14,7 +14,7 @@ struct grant_table_arch {
     gfn_t *status_gfn;
 };
 
-void gnttab_clear_flag(unsigned long nr, uint16_t *addr);
+void gnttab_clear_flag(struct domain *d, unsigned long nr, uint16_t *addr);
 int create_grant_host_mapping(unsigned long gpaddr,
         unsigned long mfn, unsigned int flags, unsigned int
         cache_flags);
diff --git a/xen/include/asm-x86/grant_table.h b/xen/include/asm-x86/grant_table.h
index 66e9742003..c22cfe81b8 100644
--- a/xen/include/asm-x86/grant_table.h
+++ b/xen/include/asm-x86/grant_table.h
@@ -84,7 +84,8 @@ static inline unsigned int gnttab_dom0_max(void)
 
 #define gnttab_mark_dirty(d, f) paging_mark_dirty((d), _mfn(f))
 
-static inline void gnttab_clear_flag(unsigned int nr, uint16_t *st)
+static inline void gnttab_clear_flag(struct domain *d, unsigned int nr,
+                                     uint16_t *st)
 {
     /*
      * Note that this cannot be clear_bit(), as the access must be
-- 
2.17.1
xsa295/4.10-19.patch (application/octet-stream, 4.1 KB)
From 80265d1a949ce7b6f5d93782af368fb82edf9a70 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:29 +0100
Subject: [PATCH v2 4.10 19/20] xen/arm: Add performance counters in guest
 atomic helpers

Add performance counters in guest atomic helpers to be able to detect
whether a guest is often paused during the operations.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Acked-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/guest_atomics.h | 12 ++++++++++++
 xen/include/asm-arm/perfc_defn.h    |  3 +++
 2 files changed, 15 insertions(+)

diff --git a/xen/include/asm-arm/guest_atomics.h b/xen/include/asm-arm/guest_atomics.h
index 61925d313d..698508bf87 100644
--- a/xen/include/asm-arm/guest_atomics.h
+++ b/xen/include/asm-arm/guest_atomics.h
@@ -24,9 +24,13 @@ DECLARE_PER_CPU(unsigned int, guest_safe_atomic_max);
 #define guest_bitop(name)                                                   \
 static inline void guest_##name(struct domain *d, int nr, volatile void *p) \
 {                                                                           \
+    perfc_incr(atomics_guest);                                              \
+                                                                            \
     if ( name##_timeout(nr, p, this_cpu(guest_safe_atomic_max)) )           \
         return;                                                             \
                                                                             \
+    perfc_incr(atomics_guest_paused);                                       \
+                                                                            \
     domain_pause_nosync(d);                                                 \
     name(nr, p);                                                            \
     domain_unpause(d);                                                      \
@@ -38,11 +42,15 @@ static inline int guest_##name(struct domain *d, int nr, volatile void *p)  \
     bool succeed;                                                           \
     int oldbit;                                                             \
                                                                             \
+    perfc_incr(atomics_guest);                                              \
+                                                                            \
     succeed = name##_timeout(nr, p, &oldbit,                                \
                              this_cpu(guest_safe_atomic_max));              \
     if ( succeed )                                                          \
         return oldbit;                                                      \
                                                                             \
+    perfc_incr(atomics_guest_paused);                                       \
+                                                                            \
     domain_pause_nosync(d);                                                 \
     oldbit = name(nr, p);                                                   \
     domain_unpause(d);                                                      \
@@ -73,10 +81,14 @@ static inline unsigned long __guest_cmpxchg(struct domain *d,
 {
     unsigned long oldval = old;
 
+    perfc_incr(atomics_guest);
+
     if ( __cmpxchg_mb_timeout(ptr, &oldval, new, size,
                               this_cpu(guest_safe_atomic_max)) )
         return oldval;
 
+    perfc_incr(atomics_guest_paused);
+
     domain_pause_nosync(d);
     oldval = __cmpxchg_mb(ptr, old, new, size);
     domain_unpause(d);
diff --git a/xen/include/asm-arm/perfc_defn.h b/xen/include/asm-arm/perfc_defn.h
index 87866264ca..dfa978112d 100644
--- a/xen/include/asm-arm/perfc_defn.h
+++ b/xen/include/asm-arm/perfc_defn.h
@@ -72,6 +72,9 @@ PERFCOUNTER(phys_timer_irqs,  "Physical timer interrupts")
 PERFCOUNTER(virt_timer_irqs,  "Virtual timer interrupts")
 PERFCOUNTER(maintenance_irqs, "Maintenance interrupts")
 
+PERFCOUNTER(atomics_guest,    "atomics: guest access")
+PERFCOUNTER(atomics_guest_paused,   "atomics: guest paused")
+
 /*#endif*/ /* __XEN_PERFC_DEFN_H__ */
 
 /*
-- 
2.17.1
xsa295/4.10-20.patch (application/octet-stream, 6.4 KB)
From b6ef87b7640b4ad6cb15500dc475f372a872f773 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:30 +0100
Subject: [PATCH v2 4.10 20/20] xen/arm: grant-table: Protect gnttab_clear_flag
 against guest misbehavior

The function gnttab_clear_flag is used to clear the access flags. On
Arm, it is implemented using a loop and guest_cmpxchg.

It is possible that guest_cmpxchg will always return a different value
than old. This can happen if the guest updated the memory before Xen has
time to do the exchange. Because of that, there are no way for to
promise the loop will end.

It is possible to make the current code safe by re-using the same
principle as applied on the guest atomic helper. However this patch
takes a different approach that should lead to more efficient code in
the default case.

A new helper is introduced to clear a set of bits on a 16-bits word.
This should avoid a an extra loop to check cmpxchg succeeded.

Note that a mask is used instead of a bit, so the helper can be re-used
later on for clearing multiple flags at the same time.

This is part of XSA-295.

Reported-by: Andrew Cooper <[email protected]>
Signed-off-by: Julien Grall <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/arm32/lib/bitops.c     | 35 +++++++++++++++++++++++++++++
 xen/arch/arm/arm64/lib/bitops.c     | 33 +++++++++++++++++++++++++++
 xen/arch/arm/mm.c                   | 10 +--------
 xen/include/asm-arm/bitops.h        |  4 ++++
 xen/include/asm-arm/guest_atomics.h | 13 +++++++++++
 5 files changed, 86 insertions(+), 9 deletions(-)

diff --git a/xen/arch/arm/arm32/lib/bitops.c b/xen/arch/arm/arm32/lib/bitops.c
index 08750314fc..3dca769bf0 100644
--- a/xen/arch/arm/arm32/lib/bitops.c
+++ b/xen/arch/arm/arm32/lib/bitops.c
@@ -126,6 +126,41 @@ testop(test_and_change_bit, eor)
 testop(test_and_clear_bit, bic)
 testop(test_and_set_bit, orr)
 
+static always_inline bool int_clear_mask16(uint16_t mask, volatile uint16_t *p,
+                                           bool timeout, unsigned int max_try)
+{
+    unsigned long res, tmp;
+
+    prefetchw((const uint16_t *)p);
+
+    do
+    {
+        asm volatile ("// int_clear_mask16\n"
+        "   ldrexh  %2, %1\n"
+        "   bic     %2, %2, %3\n"
+        "   strexh  %0, %2, %1\n"
+        : "=&r" (res), "+Qo" (*p), "=&r" (tmp)
+        : "r" (mask));
+
+        if ( !res )
+            break;
+    } while ( !timeout || ((--max_try) > 0) );
+
+    return !res;
+}
+
+void clear_mask16(uint16_t mask, volatile void *p)
+{
+    if ( !int_clear_mask16(mask, p, false, 0) )
+        ASSERT_UNREACHABLE();
+}
+
+bool clear_mask16_timeout(uint16_t mask, volatile void *p,
+                          unsigned int max_try)
+{
+    return int_clear_mask16(mask, p, true, max_try);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
index 78bf4ed8c5..27688e5418 100644
--- a/xen/arch/arm/arm64/lib/bitops.c
+++ b/xen/arch/arm/arm64/lib/bitops.c
@@ -118,6 +118,39 @@ testop(test_and_change_bit, eor)
 testop(test_and_clear_bit, bic)
 testop(test_and_set_bit, orr)
 
+static always_inline bool int_clear_mask16(uint16_t mask, volatile uint16_t *p,
+                                           bool timeout, unsigned int max_try)
+{
+    unsigned long res, tmp;
+
+    do
+    {
+        asm volatile ("//  int_clear_mask16\n"
+        "   ldxrh   %w2, %1\n"
+        "   bic     %w2, %w2, %w3\n"
+        "   stxrh   %w0, %w2, %1\n"
+        : "=&r" (res), "+Q" (*p), "=&r" (tmp)
+        : "r" (mask));
+
+        if ( !res )
+            break;
+    } while ( !timeout || ((--max_try) > 0) );
+
+    return !res;
+}
+
+void clear_mask16(uint16_t mask, volatile void *p)
+{
+    if ( !int_clear_mask16(mask, p, false, 0) )
+        ASSERT_UNREACHABLE();
+}
+
+bool clear_mask16_timeout(uint16_t mask, volatile void *p,
+                          unsigned int max_try)
+{
+    return int_clear_mask16(mask, p, true, max_try);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 097a6424a4..cbc0e7c739 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -1405,15 +1405,7 @@ void put_page_type(struct page_info *page)
 
 void gnttab_clear_flag(struct domain *d, unsigned long nr, uint16_t *addr)
 {
-    /*
-     * Note that this cannot be clear_bit(), as the access must be
-     * confined to the specified 2 bytes.
-     */
-    uint16_t mask = ~(1 << nr), old;
-
-    do {
-        old = *addr;
-    } while (guest_cmpxchg(d, addr, old, old & mask) != old);
+    guest_clear_mask16(d, BIT(nr), addr);
 }
 
 void gnttab_mark_dirty(struct domain *d, unsigned long l)
diff --git a/xen/include/asm-arm/bitops.h b/xen/include/asm-arm/bitops.h
index f6782b33be..f989bc726c 100644
--- a/xen/include/asm-arm/bitops.h
+++ b/xen/include/asm-arm/bitops.h
@@ -53,6 +53,8 @@ int test_and_set_bit(int nr, volatile void *p);
 int test_and_clear_bit(int nr, volatile void *p);
 int test_and_change_bit(int nr, volatile void *p);
 
+void clear_mask16(uint16_t mask, volatile void *p);
+
 /*
  * The helpers below may fail to update the memory if the action takes
  * too long.
@@ -71,6 +73,8 @@ bool test_and_clear_bit_timeout(int nr, volatile void *p,
                                 int *oldbit, unsigned int max_try);
 bool test_and_change_bit_timeout(int nr, volatile void *p,
                                  int *oldbit, unsigned int max_try);
+bool clear_mask16_timeout(uint16_t mask, volatile void *p,
+                          unsigned int max_try);
 
 /**
  * __test_and_set_bit - Set a bit and return its old value
diff --git a/xen/include/asm-arm/guest_atomics.h b/xen/include/asm-arm/guest_atomics.h
index 698508bf87..af27cc627b 100644
--- a/xen/include/asm-arm/guest_atomics.h
+++ b/xen/include/asm-arm/guest_atomics.h
@@ -73,6 +73,19 @@ guest_testop(test_and_change_bit)
 
 #undef guest_testop
 
+static inline void guest_clear_mask16(struct domain *d, uint16_t mask,
+                                      volatile uint16_t *p)
+{
+    perfc_incr(atomics_guest);
+
+    if ( clear_mask16_timeout(mask, p, this_cpu(guest_safe_atomic_max)) )
+        return;
+
+    domain_pause_nosync(d);
+    clear_mask16(mask, p);
+    domain_unpause(d);
+}
+
 static inline unsigned long __guest_cmpxchg(struct domain *d,
                                             volatile void *ptr,
                                             unsigned long old,
-- 
2.17.1
xsa295/4.11-01.patch (application/octet-stream, 2.6 KB)
From 66db8e4c095491ae795c8eebafd778b2dab6513d Mon Sep 17 00:00:00 2001
From: Jan Beulich <[email protected]>
Date: Tue, 12 Mar 2019 14:40:24 +0100
Subject: [PATCH v2 4.11 01/20] events: drop arch_evtchn_inject()

Have the only user call vcpu_mark_events_pending() instead, at the same
time arranging for correct ordering of the writes (evtchn_pending_sel
should be written before evtchn_upcall_pending).

Signed-off-by: Jan Beulich <[email protected]>
Reviewed-by: Andrew Cooper <[email protected]>
Reviewed-by: Julien Grall <[email protected]>
---
 xen/arch/arm/vgic.c      | 5 -----
 xen/arch/arm/vgic/vgic.c | 5 -----
 xen/common/domain.c      | 3 +--
 xen/include/xen/event.h  | 3 ---
 4 files changed, 1 insertion(+), 15 deletions(-)

diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 3fafdd0b66..07c704edff 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -597,11 +597,6 @@ out:
     return;
 }
 
-void arch_evtchn_inject(struct vcpu *v)
-{
-    vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, true);
-}
-
 bool vgic_evtchn_irq_pending(struct vcpu *v)
 {
     struct pending_irq *p;
diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index a35449bf11..bd4e268e57 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -692,11 +692,6 @@ void vgic_kick_vcpus(struct domain *d)
     }
 }
 
-void arch_evtchn_inject(struct vcpu *v)
-{
-    vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, true);
-}
-
 bool vgic_evtchn_irq_pending(struct vcpu *v)
 {
     struct vgic_irq *irq;
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 6cbf135457..f0458c200f 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -1239,10 +1239,9 @@ int map_vcpu_info(struct vcpu *v, unsigned long gfn, unsigned offset)
      * Mark everything as being pending just to make sure nothing gets
      * lost.  The domain will get a spurious event, but it can cope.
      */
-    vcpu_info(v, evtchn_upcall_pending) = 1;
     for ( i = 0; i < BITS_PER_EVTCHN_WORD(d); i++ )
         set_bit(i, &vcpu_info(v, evtchn_pending_sel));
-    arch_evtchn_inject(v);
+    vcpu_mark_events_pending(v);
 
     return 0;
 }
diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h
index ebb879e88d..b8152a9831 100644
--- a/xen/include/xen/event.h
+++ b/xen/include/xen/event.h
@@ -83,9 +83,6 @@ int guest_enabled_event(struct vcpu *v, uint32_t virq);
 /* Notify remote end of a Xen-attached event channel.*/
 void notify_via_xen_event_channel(struct domain *ld, int lport);
 
-/* Inject an event channel notification into the guest */
-void arch_evtchn_inject(struct vcpu *v);
-
 /*
  * Internal event channel object storage.
  *
-- 
2.17.1
xsa295/4.11-02.patch (application/octet-stream, 3.7 KB)
From 6284dd531adc18c71180b30f8c027c8ac13af945 Mon Sep 17 00:00:00 2001
From: Jan Beulich <[email protected]>
Date: Tue, 12 Mar 2019 14:40:56 +0100
Subject: [PATCH v2 4.11 02/20] common: avoid atomic read-modify-write accesses
 in map_vcpu_info()

There's no need to set the evtchn_pending_sel bits one by one. Simply
write full words with all ones.

For Arm this requires extending write_atomic() to also handle 64-bit
values; for symmetry read_atomic() gets adjusted as well.

Signed-off-by: Jan Beulich <[email protected]>
Reviewed-by: Andrew Cooper <[email protected]>
Reviewed-by: Julien Grall <[email protected]>
---
 xen/common/domain.c          |  9 ++++++---
 xen/include/asm-arm/atomic.h | 15 +++++++++++++++
 2 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/xen/common/domain.c b/xen/common/domain.c
index f0458c200f..6ee2bba753 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -1186,7 +1186,6 @@ int map_vcpu_info(struct vcpu *v, unsigned long gfn, unsigned offset)
     void *mapping;
     vcpu_info_t *new_info;
     struct page_info *page;
-    int i;
 
     if ( offset > (PAGE_SIZE - sizeof(vcpu_info_t)) )
         return -EINVAL;
@@ -1239,8 +1238,12 @@ int map_vcpu_info(struct vcpu *v, unsigned long gfn, unsigned offset)
      * Mark everything as being pending just to make sure nothing gets
      * lost.  The domain will get a spurious event, but it can cope.
      */
-    for ( i = 0; i < BITS_PER_EVTCHN_WORD(d); i++ )
-        set_bit(i, &vcpu_info(v, evtchn_pending_sel));
+#ifdef CONFIG_COMPAT
+    if ( !has_32bit_shinfo(d) )
+        write_atomic(&new_info->native.evtchn_pending_sel, ~0);
+    else
+#endif
+        write_atomic(&vcpu_info(v, evtchn_pending_sel), ~0);
     vcpu_mark_events_pending(v);
 
     return 0;
diff --git a/xen/include/asm-arm/atomic.h b/xen/include/asm-arm/atomic.h
index afb3eeea5b..7b4c987fa7 100644
--- a/xen/include/asm-arm/atomic.h
+++ b/xen/include/asm-arm/atomic.h
@@ -55,6 +55,19 @@ build_atomic_write(write_int_atomic, "",  WORD, int, "r")
 #if defined (CONFIG_ARM_64)
 build_atomic_read(read_u64_atomic, "", "", uint64_t, "=r")
 build_atomic_write(write_u64_atomic, "", "", uint64_t, "r")
+#elif defined (CONFIG_ARM_32)
+static inline uint64_t read_u64_atomic(const volatile uint64_t *addr)
+{
+    uint64_t val;
+
+    asm volatile ( "ldrd %0,%H0,%1" : "=r" (val) : "m" (*addr) );
+
+    return val;
+}
+static inline void write_u64_atomic(volatile uint64_t *addr, uint64_t val)
+{
+    asm volatile ( "strd %1,%H1,%0" : "=m" (*addr) : "r" (val) );
+}
 #endif
 
 build_add_sized(add_u8_sized, "b", BYTE, uint8_t, "ri")
@@ -69,6 +82,7 @@ void __bad_atomic_size(void);
     case 1: __x = (typeof(*p))read_u8_atomic((uint8_t *)p); break;      \
     case 2: __x = (typeof(*p))read_u16_atomic((uint16_t *)p); break;    \
     case 4: __x = (typeof(*p))read_u32_atomic((uint32_t *)p); break;    \
+    case 8: __x = (typeof(*p))read_u64_atomic((uint64_t *)p); break;    \
     default: __x = 0; __bad_atomic_size(); break;                       \
     }                                                                   \
     __x;                                                                \
@@ -80,6 +94,7 @@ void __bad_atomic_size(void);
     case 1: write_u8_atomic((uint8_t *)p, (uint8_t)__x); break;         \
     case 2: write_u16_atomic((uint16_t *)p, (uint16_t)__x); break;      \
     case 4: write_u32_atomic((uint32_t *)p, (uint32_t)__x); break;      \
+    case 8: write_u64_atomic((uint64_t *)p, (uint64_t)__x); break;      \
     default: __bad_atomic_size(); break;                                \
     }                                                                   \
     __x;                                                                \
-- 
2.17.1
xsa295/4.11-03.patch (application/octet-stream, 2.1 KB)
From 71df6499812025175e37781e161d90c0e3b43f3c Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:16 +0100
Subject: [PATCH v2 4.11 03/20] xen/arm: Add an isb() before reading CNTPCT_EL0
 to prevent re-ordering

Per D8.2.1 in ARM DDI 0487C.a, "a read to CNTPCT_EL0 can occur
speculatively and out of order relative to other instructions executed
on the same PE."

Add an instruction barrier to get accurate number of cycles when
requested in get_cycles(). For the other users of CNPCT_EL0, replace by
a call to get_cycles().

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Acked-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/time.c        | 4 ++--
 xen/include/asm-arm/time.h | 5 ++++-
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/time.c b/xen/arch/arm/time.c
index c11fcfeadd..a15b4a0dc7 100644
--- a/xen/arch/arm/time.c
+++ b/xen/arch/arm/time.c
@@ -149,7 +149,7 @@ void __init preinit_xen_time(void)
     if ( res )
         panic("Timer: Cannot initialize platform timer");
 
-    boot_count = READ_SYSREG64(CNTPCT_EL0);
+    boot_count = get_cycles();
 }
 
 static void __init init_dt_xen_time(void)
@@ -190,7 +190,7 @@ int __init init_xen_time(void)
 /* Return number of nanoseconds since boot */
 s_time_t get_s_time(void)
 {
-    uint64_t ticks = READ_SYSREG64(CNTPCT_EL0) - boot_count;
+    uint64_t ticks = get_cycles() - boot_count;
     return ticks_to_ns(ticks);
 }
 
diff --git a/xen/include/asm-arm/time.h b/xen/include/asm-arm/time.h
index 5b9a31de91..ca30406669 100644
--- a/xen/include/asm-arm/time.h
+++ b/xen/include/asm-arm/time.h
@@ -1,6 +1,8 @@
 #ifndef __ARM_TIME_H__
 #define __ARM_TIME_H__
 
+#include <asm/system.h>
+
 #define DT_MATCH_TIMER                      \
     DT_MATCH_COMPATIBLE("arm,armv7-timer"), \
     DT_MATCH_COMPATIBLE("arm,armv8-timer")
@@ -9,7 +11,8 @@ typedef unsigned long cycles_t;
 
 static inline cycles_t get_cycles (void)
 {
-        return 0;
+        isb();
+        return READ_SYSREG64(CNTPCT_EL0);
 }
 
 /* List of timer's IRQ */
-- 
2.17.1
xsa295/4.11-04.patch (application/octet-stream, 6.6 KB)
From 7e481e7147f81cc739611670e30a03c9d7e06c5b Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:17 +0100
Subject: [PATCH v2 4.11 04/20] xen/grant_table: Rework the prototype of
 _set_status* for lisibility

It is not clear from the parameters name whether domid and gt_version
correspond to the local or remote domain. A follow-up patch will make
them more confusing.

So rename domid (resp. gt_version) to ldomid (resp. rgt_version). At
the same time re-order the parameters to hopefully make it more
readable.

This is part of XSA-295.

Suggested-by: Jan Beulich <[email protected]>
Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Jan Beulich <[email protected]>
Acked-by: Stefano Stabellini <[email protected]>
---
 xen/common/grant_table.c | 57 ++++++++++++++++++++--------------------
 1 file changed, 28 insertions(+), 29 deletions(-)

diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index 656fad1b42..c3a806fe47 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -652,11 +652,11 @@ static unsigned int nr_grant_entries(struct grant_table *gt)
     return 0;
 }
 
-static int _set_status_v1(domid_t  domid,
+static int _set_status_v1(const grant_entry_header_t *shah,
+                          struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
-                          grant_entry_header_t *shah,
-                          struct active_grant_entry *act)
+                          domid_t  ldomid)
 {
     int rc = GNTST_okay;
     union grant_combo scombo, prev_scombo, new_scombo;
@@ -691,11 +691,11 @@ static int _set_status_v1(domid_t  domid,
         if ( !act->pin &&
              (((scombo.shorts.flags & mask) !=
                GTF_permit_access) ||
-              (scombo.shorts.domid != domid)) )
+              (scombo.shorts.domid != ldomid)) )
             PIN_FAIL(done, GNTST_general_error,
                      "Bad flags (%x) or dom (%d); expected d%d\n",
                      scombo.shorts.flags, scombo.shorts.domid,
-                     domid);
+                     ldomid);
 
         new_scombo = scombo;
         new_scombo.shorts.flags |= GTF_reading;
@@ -724,12 +724,12 @@ done:
     return rc;
 }
 
-static int _set_status_v2(domid_t  domid,
+static int _set_status_v2(const grant_entry_header_t *shah,
+                          grant_status_t *status,
+                          struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
-                          grant_entry_header_t *shah,
-                          struct active_grant_entry *act,
-                          grant_status_t *status)
+                          domid_t  ldomid)
 {
     int      rc    = GNTST_okay;
     union grant_combo scombo;
@@ -755,10 +755,10 @@ static int _set_status_v2(domid_t  domid,
     if ( !act->pin &&
          ( (((flags & mask) != GTF_permit_access) &&
             ((flags & mask) != GTF_transitive)) ||
-          (id != domid)) )
+          (id != ldomid)) )
         PIN_FAIL(done, GNTST_general_error,
                  "Bad flags (%x) or dom (%d); expected d%d, flags %x\n",
-                 flags, id, domid, mask);
+                 flags, id, ldomid, mask);
 
     if ( readonly )
     {
@@ -785,14 +785,14 @@ static int _set_status_v2(domid_t  domid,
     {
         if ( (((flags & mask) != GTF_permit_access) &&
               ((flags & mask) != GTF_transitive)) ||
-             (id != domid) ||
+             (id != ldomid) ||
              (!readonly && (flags & GTF_readonly)) )
         {
             gnttab_clear_flag(_GTF_writing, status);
             gnttab_clear_flag(_GTF_reading, status);
             PIN_FAIL(done, GNTST_general_error,
                      "Unstable flags (%x) or dom (%d); expected d%d (r/w: %d)\n",
-                     flags, id, domid, !readonly);
+                     flags, id, ldomid, !readonly);
         }
     }
     else
@@ -810,19 +810,19 @@ done:
 }
 
 
-static int _set_status(unsigned gt_version,
-                       domid_t  domid,
+static int _set_status(const grant_entry_header_t *shah,
+                       grant_status_t *status,
+                       unsigned rgt_version,
+                       struct active_grant_entry *act,
                        int readonly,
                        int mapflag,
-                       grant_entry_header_t *shah,
-                       struct active_grant_entry *act,
-                       grant_status_t *status)
+                       domid_t ldomid)
 {
 
-    if ( gt_version == 1 )
-        return _set_status_v1(domid, readonly, mapflag, shah, act);
+    if ( rgt_version == 1 )
+        return _set_status_v1(shah, act, readonly, mapflag, ldomid);
     else
-        return _set_status_v2(domid, readonly, mapflag, shah, act, status);
+        return _set_status_v2(shah, status, act, readonly, mapflag, ldomid);
 }
 
 static struct active_grant_entry *grant_map_exists(const struct domain *ld,
@@ -994,9 +994,9 @@ map_grant_ref(
          (!(op->flags & GNTMAP_readonly) &&
           !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask))) )
     {
-        if ( (rc = _set_status(rgt->gt_version, ld->domain_id,
-                               op->flags & GNTMAP_readonly,
-                               1, shah, act, status) ) != GNTST_okay )
+        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+                               op->flags & GNTMAP_readonly, 1,
+                               ld->domain_id) != GNTST_okay) )
             goto act_release_out;
 
         if ( !act->pin )
@@ -2452,8 +2452,8 @@ acquire_grant_for_copy(
     {
         if ( (!old_pin || (!readonly &&
                            !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)))) &&
-             (rc = _set_status_v2(ldom, readonly, 0, shah, act,
-                                  status)) != GNTST_okay )
+             (rc = _set_status_v2(shah, status, act, readonly, 0,
+                                  ldom)) != GNTST_okay )
             goto unlock_out;
 
         if ( !allow_transitive )
@@ -2553,9 +2553,8 @@ acquire_grant_for_copy(
     else if ( !old_pin ||
               (!readonly && !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask))) )
     {
-        if ( (rc = _set_status(rgt->gt_version, ldom,
-                               readonly, 0, shah, act,
-                               status) ) != GNTST_okay )
+        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+                               readonly, 0, ldom)) != GNTST_okay )
              goto unlock_out;
 
         td = rd;
-- 
2.17.1
xsa295/4.11-05.patch (application/octet-stream, 7.8 KB)
From 7e536ea72c87b76f13144d3713d5696d94b777f5 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:18 +0100
Subject: [PATCH v2 4.11 05/20] xen/arm64: bitops: Rewrite bitop helpers in C

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/README.LinuxPrimitives |  1 -
 xen/arch/arm/arm64/lib/bitops.S     | 67 ---------------------
 xen/arch/arm/arm64/lib/bitops.c     | 90 +++++++++++++++++++++++++++++
 3 files changed, 90 insertions(+), 68 deletions(-)
 delete mode 100644 xen/arch/arm/arm64/lib/bitops.S
 create mode 100644 xen/arch/arm/arm64/lib/bitops.c

diff --git a/xen/arch/arm/README.LinuxPrimitives b/xen/arch/arm/README.LinuxPrimitives
index 028e8721f9..891667a5da 100644
--- a/xen/arch/arm/README.LinuxPrimitives
+++ b/xen/arch/arm/README.LinuxPrimitives
@@ -8,7 +8,6 @@ arm64:
 
 bitops: last sync @ v3.16-rc6 (last commit: 8715466b6027)
 
-linux/arch/arm64/lib/bitops.S           xen/arch/arm/arm64/lib/bitops.S
 linux/arch/arm64/include/asm/bitops.h   xen/include/asm-arm/arm64/bitops.h
 
 ---------------------------------------------------------------------
diff --git a/xen/arch/arm/arm64/lib/bitops.S b/xen/arch/arm/arm64/lib/bitops.S
deleted file mode 100644
index 6471dd1875..0000000000
--- a/xen/arch/arm/arm64/lib/bitops.S
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Based on linux/arch/arm64/lib/bitops.h which in turn is
- * Based on arch/arm/lib/bitops.h
- *
- * Copyright (C) 2013 ARM Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * x0: bits 4:0  bit offset
- *     bits 31:5 word offset
- * x1: address
- */
-	.macro	bitop, name, instr
-ENTRY(	\name	)
-	and	w3, w0, #31		// Get bit offset
-	eor	w0, w0, w3		// Clear low bits
-	mov	x2, #1
-	add	x1, x1, x0, lsr #3	// Get word offset
-	lsl	x3, x2, x3		// Create mask
-1:	ldxr	w2, [x1]
-	\instr	w2, w2, w3
-	stxr	w0, w2, [x1]
-	cbnz	w0, 1b
-	ret
-ENDPROC(\name	)
-	.endm
-
-	.macro	testop, name, instr
-ENTRY(	\name	)
-	and	w3, w0, #31		// Get bit offset
-	eor	w0, w0, w3		// Clear low bits
-	mov	x2, #1
-	add	x1, x1, x0, lsr #3	// Get word offset
-	lsl	x4, x2, x3		// Create mask
-1:	ldxr	w2, [x1]
-	lsr	w0, w2, w3		// Save old value of bit
-	\instr	w2, w2, w4		// toggle bit
-	stlxr	w5, w2, [x1]
-	cbnz	w5, 1b
-	dmb	ish
-	and	w0, w0, #1
-3:	ret
-ENDPROC(\name	)
-	.endm
-
-/*
- * Atomic bit operations.
- */
-	bitop	change_bit, eor
-	bitop	clear_bit, bic
-	bitop	set_bit, orr
-
-	testop	test_and_change_bit, eor
-	testop	test_and_clear_bit, bic
-	testop	test_and_set_bit, orr
diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
new file mode 100644
index 0000000000..b1c681c642
--- /dev/null
+++ b/xen/arch/arm/arm64/lib/bitops.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/bitops.h>
+#include <asm/system.h>
+
+/*
+ * The atomic bit operations pass the number of bit in a signed number
+ * (not sure why). This has the drawback to increase the complexity of
+ * the resulting assembly.
+ *
+ * To generate simpler code, the number of bit (nr) will be cast to
+ * unsigned int.
+ *
+ * XXX: Rework the interface to use unsigned int.
+ */
+
+#define bitop(name, instr)                                                  \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
+    unsigned long res, tmp;                                                 \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldxr    %w2, %1\n"                                              \
+        "   " __stringify(instr) "     %w2, %w2, %w3\n"                     \
+        "   stxr    %w0, %w2, %1\n"                                         \
+        : "=&r" (res), "+Q" (*ptr), "=&r" (tmp)                             \
+        : "r" (mask));                                                      \
+    } while ( res );                                                        \
+}                                                                           \
+
+#define testop(name, instr)                                                 \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
+    const uint32_t mask = BIT_MASK(bit);                                    \
+    unsigned long res, tmp;                                                 \
+    unsigned long oldbit;                                                   \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldxr    %w3, %2\n"                                              \
+        "   lsr     %w1, %w3, %w5 // Save old value of bit\n"               \
+        "   " __stringify(instr) "  %w3, %w3, %w4 // Toggle bit\n"          \
+        "   stlxr   %w0, %w3, %2\n"                                         \
+        : "=&r" (res), "=&r" (oldbit), "+Q" (*ptr), "=&r" (tmp)             \
+        : "r" (mask), "r" (bit)                                             \
+        : "memory");                                                        \
+    } while ( res );                                                        \
+                                                                            \
+    dmb(ish);                                                               \
+                                                                            \
+    return oldbit & 1;                                                      \
+}
+
+bitop(change_bit, eor)
+bitop(clear_bit, bic)
+bitop(set_bit, orr)
+
+testop(test_and_change_bit, eor)
+testop(test_and_clear_bit, bic)
+testop(test_and_set_bit, orr)
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.17.1
xsa295/4.11-06.patch (application/octet-stream, 15.5 KB)
From d7519197af2489a856fd928541e32b29a74f85ba Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:19 +0100
Subject: [PATCH v2 4.11 06/20] xen/arm32: bitops: Rewrite bitop helpers in C

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/README.LinuxPrimitives    |  14 +---
 xen/arch/arm/arm32/lib/Makefile        |   5 +-
 xen/arch/arm/arm32/lib/bitops.c        |  98 +++++++++++++++++++++++
 xen/arch/arm/arm32/lib/bitops.h        | 104 -------------------------
 xen/arch/arm/arm32/lib/changebit.S     |  14 ----
 xen/arch/arm/arm32/lib/clearbit.S      |  14 ----
 xen/arch/arm/arm32/lib/setbit.S        |  15 ----
 xen/arch/arm/arm32/lib/testchangebit.S |  15 ----
 xen/arch/arm/arm32/lib/testclearbit.S  |  15 ----
 xen/arch/arm/arm32/lib/testsetbit.S    |  15 ----
 xen/include/asm-arm/arm32/bitops.h     |  19 ++---
 11 files changed, 108 insertions(+), 220 deletions(-)
 create mode 100644 xen/arch/arm/arm32/lib/bitops.c
 delete mode 100644 xen/arch/arm/arm32/lib/bitops.h
 delete mode 100644 xen/arch/arm/arm32/lib/changebit.S
 delete mode 100644 xen/arch/arm/arm32/lib/clearbit.S
 delete mode 100644 xen/arch/arm/arm32/lib/setbit.S
 delete mode 100644 xen/arch/arm/arm32/lib/testchangebit.S
 delete mode 100644 xen/arch/arm/arm32/lib/testclearbit.S
 delete mode 100644 xen/arch/arm/arm32/lib/testsetbit.S

diff --git a/xen/arch/arm/README.LinuxPrimitives b/xen/arch/arm/README.LinuxPrimitives
index 891667a5da..664a9f89ed 100644
--- a/xen/arch/arm/README.LinuxPrimitives
+++ b/xen/arch/arm/README.LinuxPrimitives
@@ -68,19 +68,9 @@ arm32
 
 bitops: last sync @ v3.16-rc6 (last commit: c32ffce0f66e)
 
-linux/arch/arm/lib/bitops.h             xen/arch/arm/arm32/lib/bitops.h
-linux/arch/arm/lib/changebit.S          xen/arch/arm/arm32/lib/changebit.S
-linux/arch/arm/lib/clearbit.S           xen/arch/arm/arm32/lib/clearbit.S
 linux/arch/arm/lib/findbit.S            xen/arch/arm/arm32/lib/findbit.S
-linux/arch/arm/lib/setbit.S             xen/arch/arm/arm32/lib/setbit.S
-linux/arch/arm/lib/testchangebit.S      xen/arch/arm/arm32/lib/testchangebit.S
-linux/arch/arm/lib/testclearbit.S       xen/arch/arm/arm32/lib/testclearbit.S
-linux/arch/arm/lib/testsetbit.S         xen/arch/arm/arm32/lib/testsetbit.S
-
-for i in bitops.h changebit.S clearbit.S findbit.S setbit.S testchangebit.S \
-         testclearbit.S testsetbit.S; do
-    diff -u ../linux/arch/arm/lib/$i xen/arch/arm/arm32/lib/$i;
-done
+
+diff -u ../linux/arch/arm/lib/findbit.S xen/arch/arm/arm32/lib/findbit.S
 
 ---------------------------------------------------------------------
 
diff --git a/xen/arch/arm/arm32/lib/Makefile b/xen/arch/arm/arm32/lib/Makefile
index e9fbc595b9..b1457c89dc 100644
--- a/xen/arch/arm/arm32/lib/Makefile
+++ b/xen/arch/arm/arm32/lib/Makefile
@@ -1,6 +1,5 @@
 obj-y += memcpy.o memmove.o memset.o memchr.o memzero.o
-obj-y += findbit.o setbit.o
-obj-y += setbit.o clearbit.o changebit.o
-obj-y += testsetbit.o testclearbit.o testchangebit.o
+obj-y += findbit.o
+obj-y += bitops.o
 obj-y += strchr.o strrchr.o
 obj-y += lib1funcs.o lshrdi3.o div64.o
diff --git a/xen/arch/arm/arm32/lib/bitops.c b/xen/arch/arm/arm32/lib/bitops.c
new file mode 100644
index 0000000000..c69bb53037
--- /dev/null
+++ b/xen/arch/arm/arm32/lib/bitops.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/bitops.h>
+#include <xen/prefetch.h>
+#include <asm/system.h>
+
+/*
+ * The atomic bit operations pass the number of bit in a signed number
+ * (not sure why). This has the drawback to increase the complexity of
+ * the resulting assembly.
+ *
+ * To generate simpler code, the number of bit (nr) will be cast to
+ * unsigned int.
+ *
+ * XXX: Rework the interface to use unsigned int.
+ */
+
+#define bitop(name, instr)                                                  \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
+    unsigned long res, tmp;                                                 \
+                                                                            \
+    ASSERT(((vaddr_t)p & 0x3) == 0);                                        \
+    prefetchw((const void *)ptr);                                           \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldrex   %2, %1\n"                                               \
+        "   " __stringify(instr) "     %2, %2, %3\n"                        \
+        "   strex   %0, %2, %1\n"                                           \
+        : "=&r" (res), "+Qo" (*ptr), "=&r" (tmp)                            \
+        : "r" (mask));                                                      \
+    } while ( res );                                                        \
+}
+
+#define testop(name, instr)                                                 \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
+    const uint32_t mask = BIT_MASK(bit);                                    \
+    unsigned long res, tmp;                                                 \
+    int oldbit;                                                             \
+                                                                            \
+    ASSERT(((vaddr_t)p & 0x3) == 0);                                        \
+    smp_mb();                                                               \
+                                                                            \
+    prefetchw((const void *)ptr);                                           \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldrex   %3, %2\n"                                               \
+        "   lsr     %1, %3, %5 // Save old value of bit\n"                  \
+        "   " __stringify(instr) "  %3, %3, %4 // Toggle bit\n"             \
+        "   strex  %0, %3, %2\n"                                            \
+        : "=&r" (res), "=&r" (oldbit), "+Qo" (*ptr), "=&r" (tmp)            \
+        : "r" (mask), "r" (bit));                                           \
+    } while ( res );                                                        \
+                                                                            \
+    smp_mb();                                                               \
+                                                                            \
+    return oldbit & 1;                                                      \
+}                                                                           \
+
+bitop(change_bit, eor)
+bitop(clear_bit, bic)
+bitop(set_bit, orr)
+
+testop(test_and_change_bit, eor)
+testop(test_and_clear_bit, bic)
+testop(test_and_set_bit, orr)
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/arm32/lib/bitops.h b/xen/arch/arm/arm32/lib/bitops.h
deleted file mode 100644
index d5e13476f4..0000000000
--- a/xen/arch/arm/arm32/lib/bitops.h
+++ /dev/null
@@ -1,104 +0,0 @@
-
-#if __LINUX_ARM_ARCH__ >= 6
-	.macro	bitop, name, instr
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	mov	r2, #1
-	and	r3, r0, #31		@ Get bit offset
-	mov	r0, r0, lsr #5
-	add	r1, r1, r0, lsl #2	@ Get word offset
-#if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
-	.arch_extension	mp
-	ALT_SMP(W(pldw)	[r1])
-	ALT_UP(W(nop))
-#endif
-	mov	r3, r2, lsl r3
-1:	ldrex	r2, [r1]
-	\instr	r2, r2, r3
-	strex	r0, r2, [r1]
-	cmp	r0, #0
-	bne	1b
-	bx	lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-
-	.macro	testop, name, instr, store
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	mov	r2, #1
-	and	r3, r0, #31		@ Get bit offset
-	mov	r0, r0, lsr #5
-	add	r1, r1, r0, lsl #2	@ Get word offset
-	mov	r3, r2, lsl r3		@ create mask
-	smp_dmb
-#if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
-	.arch_extension	mp
-	ALT_SMP(W(pldw)	[r1])
-	ALT_UP(W(nop))
-#endif
-1:	ldrex	r2, [r1]
-	ands	r0, r2, r3		@ save old value of bit
-	\instr	r2, r2, r3		@ toggle bit
-	strex	ip, r2, [r1]
-	cmp	ip, #0
-	bne	1b
-	smp_dmb
-	cmp	r0, #0
-	movne	r0, #1
-2:	bx	lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-#else
-	.macro	bitop, name, instr
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	and	r2, r0, #31
-	mov	r0, r0, lsr #5
-	mov	r3, #1
-	mov	r3, r3, lsl r2
-	save_and_disable_irqs ip
-	ldr	r2, [r1, r0, lsl #2]
-	\instr	r2, r2, r3
-	str	r2, [r1, r0, lsl #2]
-	restore_irqs ip
-	mov	pc, lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-
-/**
- * testop - implement a test_and_xxx_bit operation.
- * @instr: operational instruction
- * @store: store instruction
- *
- * Note: we can trivially conditionalise the store instruction
- * to avoid dirtying the data cache.
- */
-	.macro	testop, name, instr, store
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	and	r3, r0, #31
-	mov	r0, r0, lsr #5
-	save_and_disable_irqs ip
-	ldr	r2, [r1, r0, lsl #2]!
-	mov	r0, #1
-	tst	r2, r0, lsl r3
-	\instr	r2, r2, r0, lsl r3
-	\store	r2, [r1]
-	moveq	r0, #0
-	restore_irqs ip
-	mov	pc, lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-#endif
diff --git a/xen/arch/arm/arm32/lib/changebit.S b/xen/arch/arm/arm32/lib/changebit.S
deleted file mode 100644
index 6e4ae7594a..0000000000
--- a/xen/arch/arm/arm32/lib/changebit.S
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- *  linux/arch/arm/lib/changebit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-bitop	_change_bit, eor
diff --git a/xen/arch/arm/arm32/lib/clearbit.S b/xen/arch/arm/arm32/lib/clearbit.S
deleted file mode 100644
index fda553f246..0000000000
--- a/xen/arch/arm/arm32/lib/clearbit.S
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- *  linux/arch/arm/lib/clearbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-bitop	_clear_bit, bic
diff --git a/xen/arch/arm/arm32/lib/setbit.S b/xen/arch/arm/arm32/lib/setbit.S
deleted file mode 100644
index d52f0ab65c..0000000000
--- a/xen/arch/arm/arm32/lib/setbit.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- *  linux/arch/arm/lib/setbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "assembler.h"
-#include "bitops.h"
-	.text
-
-bitop	_set_bit, orr
diff --git a/xen/arch/arm/arm32/lib/testchangebit.S b/xen/arch/arm/arm32/lib/testchangebit.S
deleted file mode 100644
index d83b04c057..0000000000
--- a/xen/arch/arm/arm32/lib/testchangebit.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- *  linux/arch/arm/lib/testchangebit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-testop	_test_and_change_bit, eor, str
diff --git a/xen/arch/arm/arm32/lib/testclearbit.S b/xen/arch/arm/arm32/lib/testclearbit.S
deleted file mode 100644
index 6f5b7b92d1..0000000000
--- a/xen/arch/arm/arm32/lib/testclearbit.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- *  linux/arch/arm/lib/testclearbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-testop	_test_and_clear_bit, bicne, strne
diff --git a/xen/arch/arm/arm32/lib/testsetbit.S b/xen/arch/arm/arm32/lib/testsetbit.S
deleted file mode 100644
index 30425a842a..0000000000
--- a/xen/arch/arm/arm32/lib/testsetbit.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- *  linux/arch/arm/lib/testsetbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-testop	_test_and_set_bit, orreq, streq
diff --git a/xen/include/asm-arm/arm32/bitops.h b/xen/include/asm-arm/arm32/bitops.h
index 8be3564540..67c4c3f55c 100644
--- a/xen/include/asm-arm/arm32/bitops.h
+++ b/xen/include/asm-arm/arm32/bitops.h
@@ -1,19 +1,12 @@
 #ifndef _ARM_ARM32_BITOPS_H
 #define _ARM_ARM32_BITOPS_H
 
-extern void _set_bit(int nr, volatile void * p);
-extern void _clear_bit(int nr, volatile void * p);
-extern void _change_bit(int nr, volatile void * p);
-extern int _test_and_set_bit(int nr, volatile void * p);
-extern int _test_and_clear_bit(int nr, volatile void * p);
-extern int _test_and_change_bit(int nr, volatile void * p);
-
-#define set_bit(n,p)              _set_bit(n,p)
-#define clear_bit(n,p)            _clear_bit(n,p)
-#define change_bit(n,p)           _change_bit(n,p)
-#define test_and_set_bit(n,p)     _test_and_set_bit(n,p)
-#define test_and_clear_bit(n,p)   _test_and_clear_bit(n,p)
-#define test_and_change_bit(n,p)  _test_and_change_bit(n,p)
+extern void set_bit(int nr, volatile void * p);
+extern void clear_bit(int nr, volatile void * p);
+extern void change_bit(int nr, volatile void * p);
+extern int test_and_set_bit(int nr, volatile void * p);
+extern int test_and_clear_bit(int nr, volatile void * p);
+extern int test_and_change_bit(int nr, volatile void * p);
 
 #define flsl fls
 
-- 
2.17.1
xsa295/4.11-07.patch (application/octet-stream, 2.7 KB)
From f2d572a74dbf78c3e0c4ae2ef87dae0110d2f3f3 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:20 +0100
Subject: [PATCH v2 4.11 07/20] xen/arm: bitops: Consolidate prototypes in one
 place

The prototype are the same between arm32 and arm64. Consolidate them in
asm-arm/bitops.h.

This change will help the introductions of new helpers in a follow-up
patch.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm32/bitops.h |  7 -------
 xen/include/asm-arm/arm64/bitops.h | 10 ----------
 xen/include/asm-arm/bitops.h       |  8 ++++++++
 3 files changed, 8 insertions(+), 17 deletions(-)

diff --git a/xen/include/asm-arm/arm32/bitops.h b/xen/include/asm-arm/arm32/bitops.h
index 67c4c3f55c..57938a5874 100644
--- a/xen/include/asm-arm/arm32/bitops.h
+++ b/xen/include/asm-arm/arm32/bitops.h
@@ -1,13 +1,6 @@
 #ifndef _ARM_ARM32_BITOPS_H
 #define _ARM_ARM32_BITOPS_H
 
-extern void set_bit(int nr, volatile void * p);
-extern void clear_bit(int nr, volatile void * p);
-extern void change_bit(int nr, volatile void * p);
-extern int test_and_set_bit(int nr, volatile void * p);
-extern int test_and_clear_bit(int nr, volatile void * p);
-extern int test_and_change_bit(int nr, volatile void * p);
-
 #define flsl fls
 
 /*
diff --git a/xen/include/asm-arm/arm64/bitops.h b/xen/include/asm-arm/arm64/bitops.h
index 6bf1922680..6cc224ad13 100644
--- a/xen/include/asm-arm/arm64/bitops.h
+++ b/xen/include/asm-arm/arm64/bitops.h
@@ -1,16 +1,6 @@
 #ifndef _ARM_ARM64_BITOPS_H
 #define _ARM_ARM64_BITOPS_H
 
-/*
- * Little endian assembly atomic bitops.
- */
-extern void set_bit(int nr, volatile void *p);
-extern void clear_bit(int nr, volatile void *p);
-extern void change_bit(int nr, volatile void *p);
-extern int test_and_set_bit(int nr, volatile void *p);
-extern int test_and_clear_bit(int nr, volatile void *p);
-extern int test_and_change_bit(int nr, volatile void *p);
-
 /* Based on linux/include/asm-generic/bitops/builtin-__ffs.h */
 /**
  * __ffs - find first bit in word.
diff --git a/xen/include/asm-arm/bitops.h b/xen/include/asm-arm/bitops.h
index 1cbfb9edb2..c69b08adf6 100644
--- a/xen/include/asm-arm/bitops.h
+++ b/xen/include/asm-arm/bitops.h
@@ -38,6 +38,14 @@
 # error "unknown ARM variant"
 #endif
 
+/* Atomics bitops */
+void set_bit(int nr, volatile void *p);
+void clear_bit(int nr, volatile void *p);
+void change_bit(int nr, volatile void *p);
+int test_and_set_bit(int nr, volatile void *p);
+int test_and_clear_bit(int nr, volatile void *p);
+int test_and_change_bit(int nr, volatile void *p);
+
 /**
  * __test_and_set_bit - Set a bit and return its old value
  * @nr: Bit to set
-- 
2.17.1
xsa295/4.11-08.patch (application/octet-stream, 3.7 KB)
From 550682d9a82f7e32e64b38b78ee58f17ab0f9559 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Wed, 22 May 2019 13:37:53 -0700
Subject: [PATCH v2 4.11 08/20] xen/arm64: cmpxchg: Simplify the cmpxchg
 implementation

The only difference between each case of the cmpxchg is the size of
used. Rather than duplicating the code, provide a macro to generate each
cases.

This makes the code easier to read and modify.

This is part of XSA-295.

Signed-off-by; Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm64/cmpxchg.h | 98 +++++++++++------------------
 1 file changed, 36 insertions(+), 62 deletions(-)

diff --git a/xen/include/asm-arm/arm64/cmpxchg.h b/xen/include/asm-arm/arm64/cmpxchg.h
index ae42b2f5ff..393fbca6a5 100644
--- a/xen/include/asm-arm/arm64/cmpxchg.h
+++ b/xen/include/asm-arm/arm64/cmpxchg.h
@@ -61,80 +61,54 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
 	__ret; \
 })
 
-extern void __bad_cmpxchg(volatile void *ptr, int size);
+extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
+
+#define __CMPXCHG_CASE(w, sz, name)					\
+static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
+						  unsigned long old,	\
+						  unsigned long new)	\
+{									\
+	unsigned long res, oldval;					\
+									\
+	do {								\
+		asm volatile("// __cmpxchg_case_" #name "\n"		\
+		"	ldxr" #sz "	%" #w "1, %2\n"			\
+		"	mov	%w0, #0\n"				\
+		"	cmp	%" #w "1, %" #w "3\n"			\
+		"	b.ne	1f\n"					\
+		"	stxr" #sz "	%w0, %" #w "4, %2\n"		\
+		"1:\n"							\
+		: "=&r" (res), "=&r" (oldval),				\
+		  "+Q" (*(unsigned long *)ptr)				\
+		: "Ir" (old), "r" (new)					\
+		: "cc");						\
+	} while (res);							\
+									\
+	return oldval;							\
+}
+
+__CMPXCHG_CASE(w, b, 1)
+__CMPXCHG_CASE(w, h, 2)
+__CMPXCHG_CASE(w,  , 4)
+__CMPXCHG_CASE( ,  , 8)
 
 static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 				      unsigned long new, int size)
 {
-	unsigned long oldval = 0, res;
-
 	switch (size) {
 	case 1:
-		do {
-			asm volatile("// __cmpxchg1\n"
-			"	ldxrb	%w1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%w1, %w3\n"
-			"	b.ne	1f\n"
-			"	stxrb	%w0, %w4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u8 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_1(ptr, old, new);
 	case 2:
-		do {
-			asm volatile("// __cmpxchg2\n"
-			"	ldxrh	%w1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%w1, %w3\n"
-			"	b.ne	1f\n"
-			"	stxrh	%w0, %w4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u16 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_2(ptr, old, new);
 	case 4:
-		do {
-			asm volatile("// __cmpxchg4\n"
-			"	ldxr	%w1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%w1, %w3\n"
-			"	b.ne	1f\n"
-			"	stxr	%w0, %w4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u32 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_4(ptr, old, new);
 	case 8:
-		do {
-			asm volatile("// __cmpxchg8\n"
-			"	ldxr	%1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%1, %3\n"
-			"	b.ne	1f\n"
-			"	stxr	%w0, %4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u64 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_8(ptr, old, new);
 	default:
-		__bad_cmpxchg(ptr, size);
-		oldval = 0;
+		return __bad_cmpxchg(ptr, size);
 	}
 
-	return oldval;
+	ASSERT_UNREACHABLE();
 }
 
 static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
-- 
2.17.1
xsa295/4.11-09.patch (application/octet-stream, 3.6 KB)
From b824f26e89e6c9637eefea42c16eb632b33ad6ba Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:22 +0100
Subject: [PATCH v2 4.11 09/20] xen/arm32: cmpxchg: Simplify the cmpxchg
 implementation

The only difference between each case of the cmpxchg is the size of
used. Rather than duplicating the code, provide a macro to generate each
cases.

This makes the code easier to read and modify.

While doing the rework, the case for 64-bit cmpxchg is removed. This is
unused today (already commented) and it would not be possible to use
it directly.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm32/cmpxchg.h | 84 +++++++++++------------------
 1 file changed, 31 insertions(+), 53 deletions(-)

diff --git a/xen/include/asm-arm/arm32/cmpxchg.h b/xen/include/asm-arm/arm32/cmpxchg.h
index 03e0bed3a6..471a9e3a3f 100644
--- a/xen/include/asm-arm/arm32/cmpxchg.h
+++ b/xen/include/asm-arm/arm32/cmpxchg.h
@@ -52,72 +52,50 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
  * indicated by comparing RETURN with OLD.
  */
 
-extern void __bad_cmpxchg(volatile void *ptr, int size);
+extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
+
+#define __CMPXCHG_CASE(sz, name)					\
+static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
+						  unsigned long old,	\
+						  unsigned long new)	\
+{									\
+	unsigned long oldval, res;					\
+									\
+	do {								\
+		asm volatile("@ __cmpxchg_case_" #name "\n"		\
+		"	ldrex" #sz "	%1, [%2]\n"			\
+		"	mov	%0, #0\n"				\
+		"	teq	%1, %3\n"				\
+		"	strex" #sz "eq %0, %4, [%2]\n"			\
+		: "=&r" (res), "=&r" (oldval)				\
+		: "r" (ptr), "Ir" (old), "r" (new)			\
+		: "memory", "cc");					\
+	} while (res);							\
+									\
+	return oldval;							\
+}
+
+__CMPXCHG_CASE(b, 1)
+__CMPXCHG_CASE(h, 2)
+__CMPXCHG_CASE( , 4)
 
 static always_inline unsigned long __cmpxchg(
     volatile void *ptr, unsigned long old, unsigned long new, int size)
 {
-	unsigned long oldval, res;
-
 	prefetchw((const void *)ptr);
 
 	switch (size) {
 	case 1:
-		do {
-			asm volatile("@ __cmpxchg1\n"
-			"	ldrexb	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexbeq %0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-		} while (res);
-		break;
+		return __cmpxchg_case_1(ptr, old, new);
 	case 2:
-		do {
-			asm volatile("@ __cmpxchg2\n"
-			"	ldrexh	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexheq %0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-		} while (res);
-		break;
+		return __cmpxchg_case_2(ptr, old, new);
 	case 4:
-		do {
-			asm volatile("@ __cmpxchg4\n"
-			"	ldrex	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexeq	%0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-	    } while (res);
-	    break;
-#if 0
-	case 8:
-		do {
-			asm volatile("@ __cmpxchg8\n"
-			"	ldrexd	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexdeq %0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-		} while (res);
-		break;
-#endif
+		return __cmpxchg_case_4(ptr, old, new);
 	default:
-		__bad_cmpxchg(ptr, size);
-		oldval = 0;
+		return __bad_cmpxchg(ptr, size);
 	}
 
-	return oldval;
+	ASSERT_UNREACHABLE();
 }
 
 static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
-- 
2.17.1
xsa295/4.11-10.patch (application/octet-stream, 15.3 KB)
From 307aee21ae39696bffcaf1f1e5a1434ec6a1908b Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:23 +0100
Subject: [PATCH v2 4.11 10/20] xen/arm: bitops: Implement a new set of helpers
 that can timeout

Exclusive load-store atomics should only be used between trusted
threads. As not all the guests are trusted, it may be possible to DoS
Xen when updating shared memory with guest atomically.

To prevent the infinite loop, we introduce a new set of helpers that can
timeout. The timeout is based on the maximum number of iterations.

They will be used in follow-up patch to make atomic operations
on shared memory safe.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/arm32/lib/bitops.c | 52 ++++++++++++++++++++++++++++-----
 xen/arch/arm/arm64/lib/bitops.c | 52 ++++++++++++++++++++++++++++-----
 xen/include/asm-arm/bitops.h    | 28 +++++++++++++++++-
 3 files changed, 117 insertions(+), 15 deletions(-)

diff --git a/xen/arch/arm/arm32/lib/bitops.c b/xen/arch/arm/arm32/lib/bitops.c
index c69bb53037..08750314fc 100644
--- a/xen/arch/arm/arm32/lib/bitops.c
+++ b/xen/arch/arm/arm32/lib/bitops.c
@@ -30,7 +30,8 @@
  */
 
 #define bitop(name, instr)                                                  \
-void name(int nr, volatile void *p)                                         \
+static always_inline bool int_##name(int nr, volatile void *p, bool timeout,\
+                                     unsigned int max_try)                  \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
@@ -47,17 +48,33 @@ void name(int nr, volatile void *p)                                         \
         "   strex   %0, %2, %1\n"                                           \
         : "=&r" (res), "+Qo" (*ptr), "=&r" (tmp)                            \
         : "r" (mask));                                                      \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
+                                                                            \
+    return !res;                                                            \
+}                                                                           \
+                                                                            \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    if ( !int_##name(nr, p, false, 0) )                                     \
+        ASSERT_UNREACHABLE();                                               \
+}                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p, unsigned int max_try)         \
+{                                                                           \
+    return int_##name(nr, p, true, max_try);                                \
 }
 
 #define testop(name, instr)                                                 \
-int name(int nr, volatile void *p)                                          \
+static always_inline bool int_##name(int nr, volatile void *p, int *oldbit, \
+                                     bool timeout, unsigned int max_try)    \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
     const uint32_t mask = BIT_MASK(bit);                                    \
     unsigned long res, tmp;                                                 \
-    int oldbit;                                                             \
                                                                             \
     ASSERT(((vaddr_t)p & 0x3) == 0);                                        \
     smp_mb();                                                               \
@@ -71,14 +88,35 @@ int name(int nr, volatile void *p)                                          \
         "   lsr     %1, %3, %5 // Save old value of bit\n"                  \
         "   " __stringify(instr) "  %3, %3, %4 // Toggle bit\n"             \
         "   strex  %0, %3, %2\n"                                            \
-        : "=&r" (res), "=&r" (oldbit), "+Qo" (*ptr), "=&r" (tmp)            \
+        : "=&r" (res), "=&r" (*oldbit), "+Qo" (*ptr), "=&r" (tmp)           \
         : "r" (mask), "r" (bit));                                           \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
                                                                             \
     smp_mb();                                                               \
                                                                             \
-    return oldbit & 1;                                                      \
+    *oldbit &= 1;                                                           \
+                                                                            \
+    return !res;                                                            \
+}                                                                           \
+                                                                            \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    int oldbit;                                                             \
+                                                                            \
+    if ( !int_##name(nr, p, &oldbit, false, 0) )                            \
+        ASSERT_UNREACHABLE();                                               \
+                                                                            \
+    return oldbit;                                                          \
 }                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p,                               \
+                    int *oldbit, unsigned int max_try)                      \
+{                                                                           \
+    return int_##name(nr, p, oldbit, true, max_try);                        \
+}
 
 bitop(change_bit, eor)
 bitop(clear_bit, bic)
diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
index b1c681c642..78bf4ed8c5 100644
--- a/xen/arch/arm/arm64/lib/bitops.c
+++ b/xen/arch/arm/arm64/lib/bitops.c
@@ -29,7 +29,8 @@
  */
 
 #define bitop(name, instr)                                                  \
-void name(int nr, volatile void *p)                                         \
+static always_inline bool int_##name(int nr, volatile void *p, bool timeout,\
+                                     unsigned int max_try)                  \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
@@ -43,17 +44,33 @@ void name(int nr, volatile void *p)                                         \
         "   stxr    %w0, %w2, %1\n"                                         \
         : "=&r" (res), "+Q" (*ptr), "=&r" (tmp)                             \
         : "r" (mask));                                                      \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
+                                                                            \
+    return !res;                                                            \
 }                                                                           \
+                                                                            \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    if ( !int_##name(nr, p, false, 0) )                                     \
+        ASSERT_UNREACHABLE();                                               \
+}                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p, unsigned int max_try)         \
+{                                                                           \
+    return int_##name(nr, p, true, max_try);                                \
+}
 
 #define testop(name, instr)                                                 \
-int name(int nr, volatile void *p)                                          \
+static always_inline bool int_##name(int nr, volatile void *p, int *oldbit, \
+                                     bool timeout, unsigned int max_try)    \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
     const uint32_t mask = BIT_MASK(bit);                                    \
     unsigned long res, tmp;                                                 \
-    unsigned long oldbit;                                                   \
                                                                             \
     do                                                                      \
     {                                                                       \
@@ -62,14 +79,35 @@ int name(int nr, volatile void *p)                                          \
         "   lsr     %w1, %w3, %w5 // Save old value of bit\n"               \
         "   " __stringify(instr) "  %w3, %w3, %w4 // Toggle bit\n"          \
         "   stlxr   %w0, %w3, %2\n"                                         \
-        : "=&r" (res), "=&r" (oldbit), "+Q" (*ptr), "=&r" (tmp)             \
+        : "=&r" (res), "=&r" (*oldbit), "+Q" (*ptr), "=&r" (tmp)            \
         : "r" (mask), "r" (bit)                                             \
         : "memory");                                                        \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
                                                                             \
     dmb(ish);                                                               \
                                                                             \
-    return oldbit & 1;                                                      \
+    *oldbit &= 1;                                                           \
+                                                                            \
+    return !res;                                                            \
+}                                                                           \
+                                                                            \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    int oldbit;                                                             \
+                                                                            \
+    if ( !int_##name(nr, p, &oldbit, false, 0) )                            \
+        ASSERT_UNREACHABLE();                                               \
+                                                                            \
+    return oldbit;                                                          \
+}                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p,                               \
+                    int *oldbit, unsigned int max_try)                      \
+{                                                                           \
+    return int_##name(nr, p, oldbit, true, max_try);                        \
 }
 
 bitop(change_bit, eor)
diff --git a/xen/include/asm-arm/bitops.h b/xen/include/asm-arm/bitops.h
index c69b08adf6..f6782b33be 100644
--- a/xen/include/asm-arm/bitops.h
+++ b/xen/include/asm-arm/bitops.h
@@ -38,7 +38,14 @@
 # error "unknown ARM variant"
 #endif
 
-/* Atomics bitops */
+/*
+ * Atomic bitops
+ *
+ * The helpers below *should* only be used on memory shared between
+ * trusted threads or we know the memory cannot be accessed by another
+ * thread.
+ */
+
 void set_bit(int nr, volatile void *p);
 void clear_bit(int nr, volatile void *p);
 void change_bit(int nr, volatile void *p);
@@ -46,6 +53,25 @@ int test_and_set_bit(int nr, volatile void *p);
 int test_and_clear_bit(int nr, volatile void *p);
 int test_and_change_bit(int nr, volatile void *p);
 
+/*
+ * The helpers below may fail to update the memory if the action takes
+ * too long.
+ *
+ * @max_try: Maximum number of iterations
+ *
+ * The helpers will return true when the update has succeeded (i.e no
+ * timeout) and false if the update has failed.
+ */
+bool set_bit_timeout(int nr, volatile void *p, unsigned int max_try);
+bool clear_bit_timeout(int nr, volatile void *p, unsigned int max_try);
+bool change_bit_timeout(int nr, volatile void *p, unsigned int max_try);
+bool test_and_set_bit_timeout(int nr, volatile void *p,
+                              int *oldbit, unsigned int max_try);
+bool test_and_clear_bit_timeout(int nr, volatile void *p,
+                                int *oldbit, unsigned int max_try);
+bool test_and_change_bit_timeout(int nr, volatile void *p,
+                                 int *oldbit, unsigned int max_try);
+
 /**
  * __test_and_set_bit - Set a bit and return its old value
  * @nr: Bit to set
-- 
2.17.1
xsa295/4.11-11.patch (application/octet-stream, 8.3 KB)
From 94736d1a81c259acb16eccb1b2f2f7286bf71180 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Wed, 22 May 2019 13:39:17 -0700
Subject: [PATCH v2 4.11 11/20] xen/arm: cmpxchg: Provide a new helper that can
 timeout

Exclusive load-store atomics should only be used between trusted
threads. As not all the guests are trusted, it may be possible to DoS
Xen when updating shared memory with guest atomically.

To prevent the infinite loop, we introduce a new helper that can timeout.
The timeout is based on the maximum number of iterations.

It will be used in follow-up patch to make atomic operations on shared
memory safe.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm32/cmpxchg.h | 63 +++++++++++++++++++++-----
 xen/include/asm-arm/arm64/cmpxchg.h | 70 ++++++++++++++++++++++-------
 2 files changed, 106 insertions(+), 27 deletions(-)

diff --git a/xen/include/asm-arm/arm32/cmpxchg.h b/xen/include/asm-arm/arm32/cmpxchg.h
index 471a9e3a3f..49ca2a0d7a 100644
--- a/xen/include/asm-arm/arm32/cmpxchg.h
+++ b/xen/include/asm-arm/arm32/cmpxchg.h
@@ -55,11 +55,14 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
 extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
 
 #define __CMPXCHG_CASE(sz, name)					\
-static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
-						  unsigned long old,	\
-						  unsigned long new)	\
+static inline bool __cmpxchg_case_##name(volatile void *ptr,		\
+					 unsigned long *old,		\
+					 unsigned long new,		\
+					 bool timeout,			\
+					 unsigned int max_try)		\
 {									\
-	unsigned long oldval, res;					\
+	unsigned long oldval;						\
+	unsigned long res;						\
 									\
 	do {								\
 		asm volatile("@ __cmpxchg_case_" #name "\n"		\
@@ -68,29 +71,35 @@ static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
 		"	teq	%1, %3\n"				\
 		"	strex" #sz "eq %0, %4, [%2]\n"			\
 		: "=&r" (res), "=&r" (oldval)				\
-		: "r" (ptr), "Ir" (old), "r" (new)			\
+		: "r" (ptr), "Ir" (*old), "r" (new)			\
 		: "memory", "cc");					\
-	} while (res);							\
 									\
-	return oldval;							\
+		if (!res)						\
+			break;						\
+	} while (!timeout || ((--max_try) > 0));			\
+									\
+	*old = oldval;							\
+									\
+	return !res;							\
 }
 
 __CMPXCHG_CASE(b, 1)
 __CMPXCHG_CASE(h, 2)
 __CMPXCHG_CASE( , 4)
 
-static always_inline unsigned long __cmpxchg(
-    volatile void *ptr, unsigned long old, unsigned long new, int size)
+static always_inline bool __int_cmpxchg(volatile void *ptr, unsigned long *old,
+					unsigned long new, int size,
+					bool timeout, unsigned int max_try)
 {
 	prefetchw((const void *)ptr);
 
 	switch (size) {
 	case 1:
-		return __cmpxchg_case_1(ptr, old, new);
+		return __cmpxchg_case_1(ptr, old, new, timeout, max_try);
 	case 2:
-		return __cmpxchg_case_2(ptr, old, new);
+		return __cmpxchg_case_2(ptr, old, new, timeout, max_try);
 	case 4:
-		return __cmpxchg_case_4(ptr, old, new);
+		return __cmpxchg_case_4(ptr, old, new, timeout, max_try);
 	default:
 		return __bad_cmpxchg(ptr, size);
 	}
@@ -98,6 +107,17 @@ static always_inline unsigned long __cmpxchg(
 	ASSERT_UNREACHABLE();
 }
 
+static always_inline unsigned long __cmpxchg(volatile void *ptr,
+					     unsigned long old,
+					     unsigned long new,
+					     int size)
+{
+	if (!__int_cmpxchg(ptr, &old, new, size, false, 0))
+		ASSERT_UNREACHABLE();
+
+	return old;
+}
+
 static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
                                                 unsigned long old,
                                                 unsigned long new, int size)
@@ -111,6 +131,25 @@ static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
 	return ret;
 }
 
+/*
+ * The helper may fail to update the memory if the action takes too long.
+ *
+ * @old: On call the value pointed contains the expected old value. It will be
+ * updated to the actual old value.
+ * @max_try: Maximum number of iterations
+ *
+ * The helper will return true when the update has succeeded (i.e no
+ * timeout) and false if the update has failed.
+ */
+static always_inline bool __cmpxchg_mb_timeout(volatile void *ptr,
+					       unsigned long *old,
+					       unsigned long new,
+					       int size,
+					       unsigned int max_try)
+{
+	return __int_cmpxchg(ptr, old, new, size, true, max_try);
+}
+
 #define cmpxchg(ptr,o,n)						\
 	((__typeof__(*(ptr)))__cmpxchg_mb((ptr),			\
 					  (unsigned long)(o),		\
diff --git a/xen/include/asm-arm/arm64/cmpxchg.h b/xen/include/asm-arm/arm64/cmpxchg.h
index 393fbca6a5..5bc2e1f786 100644
--- a/xen/include/asm-arm/arm64/cmpxchg.h
+++ b/xen/include/asm-arm/arm64/cmpxchg.h
@@ -64,11 +64,14 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
 extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
 
 #define __CMPXCHG_CASE(w, sz, name)					\
-static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
-						  unsigned long old,	\
-						  unsigned long new)	\
+static inline bool __cmpxchg_case_##name(volatile void *ptr,		\
+					 unsigned long *old,		\
+					 unsigned long new,		\
+					 bool timeout,			\
+					 unsigned int max_try)		\
 {									\
-	unsigned long res, oldval;					\
+	unsigned long oldval;						\
+	unsigned long res;						\
 									\
 	do {								\
 		asm volatile("// __cmpxchg_case_" #name "\n"		\
@@ -80,11 +83,16 @@ static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
 		"1:\n"							\
 		: "=&r" (res), "=&r" (oldval),				\
 		  "+Q" (*(unsigned long *)ptr)				\
-		: "Ir" (old), "r" (new)					\
+		: "Ir" (*old), "r" (new)				\
 		: "cc");						\
-	} while (res);							\
 									\
-	return oldval;							\
+		if (!res)						\
+			break;						\
+	} while (!timeout || ((--max_try) > 0));			\
+									\
+	*old = oldval;							\
+									\
+	return !res;							\
 }
 
 __CMPXCHG_CASE(w, b, 1)
@@ -92,18 +100,19 @@ __CMPXCHG_CASE(w, h, 2)
 __CMPXCHG_CASE(w,  , 4)
 __CMPXCHG_CASE( ,  , 8)
 
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
-				      unsigned long new, int size)
+static always_inline bool __int_cmpxchg(volatile void *ptr, unsigned long *old,
+					unsigned long new, int size,
+					bool timeout, unsigned int max_try)
 {
 	switch (size) {
 	case 1:
-		return __cmpxchg_case_1(ptr, old, new);
+		return __cmpxchg_case_1(ptr, old, new, timeout, max_try);
 	case 2:
-		return __cmpxchg_case_2(ptr, old, new);
+		return __cmpxchg_case_2(ptr, old, new, timeout, max_try);
 	case 4:
-		return __cmpxchg_case_4(ptr, old, new);
+		return __cmpxchg_case_4(ptr, old, new, timeout, max_try);
 	case 8:
-		return __cmpxchg_case_8(ptr, old, new);
+		return __cmpxchg_case_8(ptr, old, new, timeout, max_try);
 	default:
 		return __bad_cmpxchg(ptr, size);
 	}
@@ -111,8 +120,20 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 	ASSERT_UNREACHABLE();
 }
 
-static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
-					 unsigned long new, int size)
+static always_inline unsigned long __cmpxchg(volatile void *ptr,
+					     unsigned long old,
+					     unsigned long new,
+					     int size)
+{
+	if (!__int_cmpxchg(ptr, &old, new, size, false, 0))
+		ASSERT_UNREACHABLE();
+
+	return old;
+}
+
+static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
+						unsigned long old,
+						unsigned long new, int size)
 {
 	unsigned long ret;
 
@@ -123,6 +144,25 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
 	return ret;
 }
 
+/*
+ * The helper may fail to update the memory if the action takes too long.
+ *
+ * @old: On call the value pointed contains the expected old value. It will be
+ * updated to the actual old value.
+ * @max_try: Maximum number of iterations
+ *
+ * The helper will return true when the update has succeeded (i.e no
+ * timeout) and false if the update has failed.
+ */
+static always_inline bool __cmpxchg_mb_timeout(volatile void *ptr,
+					       unsigned long *old,
+					       unsigned long new,
+					       int size,
+					       unsigned int max_try)
+{
+	return __int_cmpxchg(ptr, old, new, size, true, max_try);
+}
+
 #define cmpxchg(ptr, o, n) \
 ({ \
 	__typeof__(*(ptr)) __ret; \
-- 
2.17.1
xsa295/4.11-12.patch (application/octet-stream, 807 B)
From fc01557fe8d60cc9a29d8f29568f940a7873d063 Mon Sep 17 00:00:00 2001
From: Xin Li <[email protected]>
Date: Tue, 9 Oct 2018 17:33:18 +0800
Subject: [PATCH v2 4.11 12/20] xen/xsm: remove unnecessary #define

this #define is unnecessary since XSM_INLINE is redefined in
xsm/dummy.h, it's a risk of build breakage, so remove it.

Signed-off-by: Xin Li <[email protected]>
Reviewed-by: Jan Beulich <[email protected]>
Acked-by: Daniel De Graaf <[email protected]>
---
 xen/xsm/dummy.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c
index 6e751199ee..f371a841c1 100644
--- a/xen/xsm/dummy.c
+++ b/xen/xsm/dummy.c
@@ -11,7 +11,6 @@
  */
 
 #define XSM_NO_WRAPPERS
-#define XSM_INLINE /* */
 #include <xsm/dummy.h>
 
 struct xsm_operations dummy_xsm_ops;
-- 
2.17.1
xsa295/4.11-13.patch (application/octet-stream, 3.8 KB)
From 046280b23fa40176006b9ab300a46452e166e6ca Mon Sep 17 00:00:00 2001
From: Xin Li <[email protected]>
Date: Tue, 9 Oct 2018 17:33:19 +0800
Subject: [PATCH v2 4.11 13/20] xen/xsm: Introduce new boot parameter xsm

Introduce new boot parameter xsm to choose which xsm module is enabled,
and set default to dummy. And add new option in Kconfig to choose the
default XSM implementation.

Signed-off-by: Xin Li <[email protected]>
Acked-by: Daniel De Graaf <[email protected]>
Acked-by: Andrew Cooper <[email protected]>
---
 docs/misc/xen-command-line.markdown | 13 +++++++++
 xen/common/Kconfig                  | 13 ++++++++-
 xen/xsm/xsm_core.c                  | 44 ++++++++++++++++++++++++++++-
 3 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/docs/misc/xen-command-line.markdown b/docs/misc/xen-command-line.markdown
index 8108bbf117..1025fb8a6b 100644
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -865,6 +865,19 @@ hardware domain is architecture dependent.
 Note that specifying zero as domU value means zero, while for dom0 it means
 to use the default.
 
+### xsm
+> `= dummy | flask`
+
+> Default: `dummy`
+
+Specify which XSM module should be enabled.  This option is only available if
+the hypervisor was compiled with XSM support.
+
+* `dummy`: this is the default choice.  Basic restriction for common deployment
+  (the dummy module) will be applied.  It's also used when XSM is compiled out.
+* `flask`: this is the policy based access control.  To choose this, the
+  separated option in kconfig must also be enabled.
+
 ### flask
 > `= permissive | enforcing | late | disabled`
 
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index 9043dce937..448c2888fe 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -105,7 +105,7 @@ config XSM
 
 config FLASK
 	def_bool y
-	prompt "FLux Advanced Security Kernel support" if EXPERT = "y"
+	prompt "FLux Advanced Security Kernel support"
 	depends on XSM
 	---help---
 	  Enables FLASK (FLux Advanced Security Kernel) as the access control
@@ -143,6 +143,17 @@ config XSM_POLICY
 
 	  If unsure, say Y.
 
+choice
+	prompt "Default XSM implementation"
+	depends on XSM
+	default XSM_FLASK_DEFAULT if XSM_FLASK
+	default XSM_DUMMY_DEFAULT
+	config XSM_DUMMY_DEFAULT
+		bool "Match non-XSM behavior"
+	config XSM_FLASK_DEFAULT
+		bool "FLux Advanced Security Kernel" if XSM_FLASK
+endchoice
+
 config LATE_HWDOM
 	bool "Dedicated hardware domain"
 	default n
diff --git a/xen/xsm/xsm_core.c b/xen/xsm/xsm_core.c
index 949dfcff75..e2f17e4b41 100644
--- a/xen/xsm/xsm_core.c
+++ b/xen/xsm/xsm_core.c
@@ -31,6 +31,35 @@
 
 struct xsm_operations *xsm_ops;
 
+enum xsm_bootparam {
+    XSM_BOOTPARAM_DUMMY,
+    XSM_BOOTPARAM_FLASK,
+};
+
+static enum xsm_bootparam __initdata xsm_bootparam =
+#ifdef CONFIG_XSM_FLASK_DEFAULT
+    XSM_BOOTPARAM_FLASK;
+#else
+    XSM_BOOTPARAM_DUMMY;
+#endif
+
+static int __init parse_xsm_param(const char *s)
+{
+    int rc = 0;
+
+    if ( !strcmp(s, "dummy") )
+        xsm_bootparam = XSM_BOOTPARAM_DUMMY;
+#ifdef CONFIG_XSM_FLASK
+    else if ( !strcmp(s, "flask") )
+        xsm_bootparam = XSM_BOOTPARAM_FLASK;
+#endif
+    else
+        rc = -EINVAL;
+
+    return rc;
+}
+custom_param("xsm", parse_xsm_param);
+
 static inline int verify(struct xsm_operations *ops)
 {
     /* verify the security_operations structure exists */
@@ -57,7 +86,20 @@ static int __init xsm_core_init(const void *policy_buffer, size_t policy_size)
     }
 
     xsm_ops = &dummy_xsm_ops;
-    flask_init(policy_buffer, policy_size);
+
+    switch ( xsm_bootparam )
+    {
+    case XSM_BOOTPARAM_DUMMY:
+        break;
+
+    case XSM_BOOTPARAM_FLASK:
+        flask_init(policy_buffer, policy_size);
+        break;
+
+    default:
+        ASSERT_UNREACHABLE();
+        break;
+    }
 
     return 0;
 }
-- 
2.17.1
xsa295/4.11-14.patch (application/octet-stream, 8.3 KB)
From 0b4a5f09333267c6ee57ff1ee99cb9e7667b55df Mon Sep 17 00:00:00 2001
From: Xin Li <[email protected]>
Date: Tue, 9 Oct 2018 17:33:20 +0800
Subject: [PATCH v2 4.11 14/20] xen/xsm: Add new SILO mode for XSM

When SILO is enabled, there would be no page-sharing or event notifications
between unprivileged VMs (no grant tables or event channels).

Signed-off-by: Xin Li <[email protected]>
Acked-by: Daniel De Graaf <[email protected]>
Acked-by: Andrew Cooper <[email protected]>
---
 docs/misc/xen-command-line.markdown |   5 +-
 xen/common/Kconfig                  |  15 ++++
 xen/include/xsm/dummy.h             |   3 +-
 xen/include/xsm/xsm.h               |   6 ++
 xen/xsm/Makefile                    |   1 +
 xen/xsm/silo.c                      | 108 ++++++++++++++++++++++++++++
 xen/xsm/xsm_core.c                  |  11 +++
 7 files changed, 147 insertions(+), 2 deletions(-)
 create mode 100644 xen/xsm/silo.c

diff --git a/docs/misc/xen-command-line.markdown b/docs/misc/xen-command-line.markdown
index 1025fb8a6b..c63a07d29b 100644
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -866,7 +866,7 @@ Note that specifying zero as domU value means zero, while for dom0 it means
 to use the default.
 
 ### xsm
-> `= dummy | flask`
+> `= dummy | flask | silo`
 
 > Default: `dummy`
 
@@ -877,6 +877,9 @@ the hypervisor was compiled with XSM support.
   (the dummy module) will be applied.  It's also used when XSM is compiled out.
 * `flask`: this is the policy based access control.  To choose this, the
   separated option in kconfig must also be enabled.
+* `silo`: this will deny any unmediated communication channels between
+  unprivileged VMs.  To choose this, the separated option in kconfig must also
+  be enabled.
 
 ### flask
 > `= permissive | enforcing | late | disabled`
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index 448c2888fe..512f6446a3 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -143,15 +143,30 @@ config XSM_POLICY
 
 	  If unsure, say Y.
 
+config XSM_SILO
+	def_bool y
+	prompt "SILO support"
+	depends on XSM
+	---help---
+	  Enables SILO as the access control mechanism used by the XSM framework.
+	  This is not the default module, add boot parameter xsm=silo to choose
+	  it. This will deny any unmediated communication channels (grant tables
+	  and event channels) between unprivileged VMs.
+
+	  If unsure, say Y.
+
 choice
 	prompt "Default XSM implementation"
 	depends on XSM
 	default XSM_FLASK_DEFAULT if XSM_FLASK
+	default XSM_SILO_DEFAULT if XSM_SILO
 	default XSM_DUMMY_DEFAULT
 	config XSM_DUMMY_DEFAULT
 		bool "Match non-XSM behavior"
 	config XSM_FLASK_DEFAULT
 		bool "FLux Advanced Security Kernel" if XSM_FLASK
+	config XSM_SILO_DEFAULT
+		bool "SILO" if XSM_SILO
 endchoice
 
 config LATE_HWDOM
diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h
index ff6b2dbf39..a507fa43f5 100644
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -48,7 +48,8 @@ void __xsm_action_mismatch_detected(void);
  * There is no xsm_default_t argument available, so the value from the assertion
  * is used to initialize the variable.
  */
-#define XSM_INLINE /* */
+#define XSM_INLINE __maybe_unused
+
 #define XSM_DEFAULT_ARG /* */
 #define XSM_DEFAULT_VOID void
 #define XSM_ASSERT_ACTION(def) xsm_default_t action = def; (void)action
diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h
index f0c6fc7e29..b16a1b5b18 100644
--- a/xen/include/xsm/xsm.h
+++ b/xen/include/xsm/xsm.h
@@ -733,6 +733,12 @@ extern const unsigned char xsm_init_policy[];
 extern const unsigned int xsm_init_policy_size;
 #endif
 
+#ifdef CONFIG_XSM_SILO
+extern void silo_init(void);
+#else
+static inline void silo_init(void) {}
+#endif
+
 #else /* CONFIG_XSM */
 
 #include <xsm/dummy.h>
diff --git a/xen/xsm/Makefile b/xen/xsm/Makefile
index 3252c46e64..50e21303b3 100644
--- a/xen/xsm/Makefile
+++ b/xen/xsm/Makefile
@@ -1,5 +1,6 @@
 obj-y += xsm_core.o
 obj-$(CONFIG_XSM) += xsm_policy.o
 obj-$(CONFIG_XSM) += dummy.o
+obj-$(CONFIG_XSM_SILO) += silo.o
 
 subdir-$(CONFIG_FLASK) += flask
diff --git a/xen/xsm/silo.c b/xen/xsm/silo.c
new file mode 100644
index 0000000000..4850756a3d
--- /dev/null
+++ b/xen/xsm/silo.c
@@ -0,0 +1,108 @@
+/******************************************************************************
+ * xsm/silo.c
+ *
+ * SILO module for XSM (Xen Security Modules)
+ *
+ * Copyright (c) 2018 Citrix Systems Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+#define XSM_NO_WRAPPERS
+#include <xsm/dummy.h>
+
+/*
+ * Check if inter-domain communication is allowed.
+ * Return true when pass check.
+ */
+static bool silo_mode_dom_check(const struct domain *ldom,
+                                const struct domain *rdom)
+{
+    const struct domain *currd = current->domain;
+
+    return (is_control_domain(currd) || is_control_domain(ldom) ||
+            is_control_domain(rdom) || ldom == rdom);
+}
+
+static int silo_evtchn_unbound(struct domain *d1, struct evtchn *chn,
+                               domid_t id2)
+{
+    int rc = -EPERM;
+    struct domain *d2 = rcu_lock_domain_by_any_id(id2);
+
+    if ( d2 == NULL )
+        rc = -ESRCH;
+    else
+    {
+        if ( silo_mode_dom_check(d1, d2) )
+            rc = xsm_evtchn_unbound(d1, chn, id2);
+        rcu_unlock_domain(d2);
+    }
+
+    return rc;
+}
+
+static int silo_evtchn_interdomain(struct domain *d1, struct evtchn *chan1,
+                                   struct domain *d2, struct evtchn *chan2)
+{
+    if ( silo_mode_dom_check(d1, d2) )
+        return xsm_evtchn_interdomain(d1, chan1, d2, chan2);
+    return -EPERM;
+}
+
+static int silo_grant_mapref(struct domain *d1, struct domain *d2,
+                             uint32_t flags)
+{
+    if ( silo_mode_dom_check(d1, d2) )
+        return xsm_grant_mapref(d1, d2, flags);
+    return -EPERM;
+}
+
+static int silo_grant_transfer(struct domain *d1, struct domain *d2)
+{
+    if ( silo_mode_dom_check(d1, d2) )
+        return xsm_grant_transfer(d1, d2);
+    return -EPERM;
+}
+
+static int silo_grant_copy(struct domain *d1, struct domain *d2)
+{
+    if ( silo_mode_dom_check(d1, d2) )
+        return xsm_grant_copy(d1, d2);
+    return -EPERM;
+}
+
+static struct xsm_operations silo_xsm_ops = {
+    .evtchn_unbound = silo_evtchn_unbound,
+    .evtchn_interdomain = silo_evtchn_interdomain,
+    .grant_mapref = silo_grant_mapref,
+    .grant_transfer = silo_grant_transfer,
+    .grant_copy = silo_grant_copy,
+};
+
+void __init silo_init(void)
+{
+    printk("Initialising XSM SILO mode\n");
+
+    if ( register_xsm(&silo_xsm_ops) )
+        panic("SILO: Unable to register with XSM\n");
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/xsm/xsm_core.c b/xen/xsm/xsm_core.c
index e2f17e4b41..7b862ea79d 100644
--- a/xen/xsm/xsm_core.c
+++ b/xen/xsm/xsm_core.c
@@ -34,11 +34,14 @@ struct xsm_operations *xsm_ops;
 enum xsm_bootparam {
     XSM_BOOTPARAM_DUMMY,
     XSM_BOOTPARAM_FLASK,
+    XSM_BOOTPARAM_SILO,
 };
 
 static enum xsm_bootparam __initdata xsm_bootparam =
 #ifdef CONFIG_XSM_FLASK_DEFAULT
     XSM_BOOTPARAM_FLASK;
+#elif CONFIG_XSM_SILO_DEFAULT
+    XSM_BOOTPARAM_SILO;
 #else
     XSM_BOOTPARAM_DUMMY;
 #endif
@@ -52,6 +55,10 @@ static int __init parse_xsm_param(const char *s)
 #ifdef CONFIG_XSM_FLASK
     else if ( !strcmp(s, "flask") )
         xsm_bootparam = XSM_BOOTPARAM_FLASK;
+#endif
+#ifdef CONFIG_XSM_SILO
+    else if ( !strcmp(s, "silo") )
+        xsm_bootparam = XSM_BOOTPARAM_SILO;
 #endif
     else
         rc = -EINVAL;
@@ -96,6 +103,10 @@ static int __init xsm_core_init(const void *policy_buffer, size_t policy_size)
         flask_init(policy_buffer, policy_size);
         break;
 
+    case XSM_BOOTPARAM_SILO:
+        silo_init();
+        break;
+
     default:
         ASSERT_UNREACHABLE();
         break;
-- 
2.17.1
xsa295/4.11-15.patch (application/octet-stream, 3.5 KB)
From 7f77f648cec9a30cfdca4222686dc999ff113789 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:25 +0100
Subject: [PATCH v2 4.11 15/20] xen/arm: Turn on SILO mode by default on Arm

On Arm, exclusive load-store atomics should only be used between trusted
thread. As not all the guests are trusted, it may be possible to DoS Xen
when updating shared memory with guest atomically.

Recent patches introduced new helpers to update shared memory with guest
atomically. Those helpers relies on a memory region to be be shared with
Xen and a single guest.

At the moment, nothing prevent a guest sharing a page with Xen and as
well with another guest (e.g via grant table).

For the scope of the XSA, the quickest way is to deny communications
between unprivileged guest. So this patch is enabling and using SILO
mode by default on Arm.

Users wanted finer graine policy could wrote their own Flask policy.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Acked-by: Jan Beulich <[email protected]>
---
 xen/arch/arm/setup.c  | 8 ++++++--
 xen/common/Kconfig    | 3 ++-
 xen/include/xsm/xsm.h | 5 +++++
 xen/xsm/xsm_core.c    | 2 +-
 4 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index 1d6f6bf37e..ff949f545a 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -37,6 +37,7 @@
 #include <xen/vmap.h>
 #include <xen/libfdt/libfdt.h>
 #include <xen/acpi.h>
+#include <xen/warning.h>
 #include <asm/alternative.h>
 #include <asm/page.h>
 #include <asm/current.h>
@@ -787,8 +788,11 @@ void __init start_xen(unsigned long boot_phys_offset,
 
     tasklet_subsys_init();
 
-
-    xsm_dt_init();
+    if ( xsm_dt_init() != 1 )
+        warning_add("WARNING: SILO mode is not enabled.\n"
+                    "It has implications on the security of the system,\n"
+                    "unless the communications have been forbidden between\n"
+                    "untrusted domains.\n");
 
     init_maintenance_interrupt();
     init_timer_interrupt();
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index 512f6446a3..e4af3f13eb 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -93,7 +93,7 @@ config XENOPROF
 
 config XSM
 	bool "Xen Security Modules support"
-	default n
+	default ARM
 	---help---
 	  Enables the security framework known as Xen Security Modules which
 	  allows administrators fine-grained control over a Xen domain and
@@ -158,6 +158,7 @@ config XSM_SILO
 choice
 	prompt "Default XSM implementation"
 	depends on XSM
+	default XSM_SILO_DEFAULT if XSM_SILO && ARM
 	default XSM_FLASK_DEFAULT if XSM_FLASK
 	default XSM_SILO_DEFAULT if XSM_SILO
 	default XSM_DUMMY_DEFAULT
diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h
index b16a1b5b18..0c803531eb 100644
--- a/xen/include/xsm/xsm.h
+++ b/xen/include/xsm/xsm.h
@@ -710,6 +710,11 @@ extern int xsm_multiboot_policy_init(unsigned long *module_map,
 #endif
 
 #ifdef CONFIG_HAS_DEVICE_TREE
+/*
+ * Initialize XSM
+ *
+ * On success, return 1 if using SILO mode else 0.
+ */
 extern int xsm_dt_init(void);
 extern int xsm_dt_policy_init(void **policy_buffer, size_t *policy_size);
 extern bool has_xsm_magic(paddr_t);
diff --git a/xen/xsm/xsm_core.c b/xen/xsm/xsm_core.c
index 7b862ea79d..1179cdf610 100644
--- a/xen/xsm/xsm_core.c
+++ b/xen/xsm/xsm_core.c
@@ -167,7 +167,7 @@ int __init xsm_dt_init(void)
 
     xfree(policy_buffer);
 
-    return ret;
+    return ret ?: (xsm_bootparam == XSM_BOOTPARAM_SILO);
 }
 
 /**
-- 
2.17.1
xsa295/4.11-16.patch (application/octet-stream, 9.6 KB)
From 63966ce61c86b68592a87353176210ab42d9f8fd Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:26 +0100
Subject: [PATCH v2 4.11 16/20] xen/bitops: Provide helpers to safely modify
 guest memory atomically

On Arm, exclusive load-store atomics should only be used between trusted
thread. As not all the guests are trusted, it may be possible to DoS Xen
when updating shared memory with guest atomically.

This patch adds a new set of helper that will update the guest memory
safely. For x86, it is already possible to use the current helpers
safely. So just wrap them.

For Arm, we will first attempt to update the guest memory with the loop
bounded by a maximum number of iterations. If it fails, we will pause the
domain and try again.

Note that this heuristics assumes that a page can only be shared between
Xen and one domain. Not Xen and multiple domain.

The maximum number of iterations is based on how many times a simple
load-store atomic operation can be executed in 1uS. The maximum value is
per-CPU to cater big.LITTLE and calculated when the CPU is booting. The
heuristic was randomly chosen and can be modified if impact too much
good-behaving guest.

Note, while test_bit does not requires to use atomic operation, a
wrapper for test_bit was added for completeness. In this case, the
domain stays constified to avoid major rework in the caller for the
time-being.

This is part of XSA-295.

Signed-of-by: Julien Grall <[email protected]>
Acked-by: Jan Beulich <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/Makefile               |  1 +
 xen/arch/arm/guest_atomics.c        | 91 +++++++++++++++++++++++++++++
 xen/include/asm-arm/guest_atomics.h | 76 ++++++++++++++++++++++++
 xen/include/asm-x86/guest_atomics.h | 30 ++++++++++
 4 files changed, 198 insertions(+)
 create mode 100644 xen/arch/arm/guest_atomics.c
 create mode 100644 xen/include/asm-arm/guest_atomics.h
 create mode 100644 xen/include/asm-x86/guest_atomics.h

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index a9533b107e..3559e3ac46 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_HAS_GICV3) += gic-v3.o
 obj-$(CONFIG_HAS_ITS) += gic-v3-its.o
 obj-$(CONFIG_HAS_ITS) += gic-v3-lpi.o
 obj-y += guestcopy.o
+obj-y += guest_atomics.o
 obj-y += guest_walk.o
 obj-y += hvm.o
 obj-y += io.o
diff --git a/xen/arch/arm/guest_atomics.c b/xen/arch/arm/guest_atomics.c
new file mode 100644
index 0000000000..1b78a062f0
--- /dev/null
+++ b/xen/arch/arm/guest_atomics.c
@@ -0,0 +1,91 @@
+/*
+ * arch/arm/guest_atomics.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <xen/cpu.h>
+
+#include <asm/guest_atomics.h>
+
+DEFINE_PER_CPU_READ_MOSTLY(unsigned int, guest_safe_atomic_max);
+
+/*
+ * Heuristic to find a safe upper-limit for load-store exclusive
+ * operations on memory shared with guest.
+ *
+ * At the moment, we calculate the number of iterations of a simple
+ * load-store atomic loop in 1uS.
+ */
+static void calibrate_safe_atomic(void)
+{
+    s_time_t deadline = NOW() + MICROSECS(1);
+    unsigned int counter = 0;
+    unsigned long mem = 0;
+
+    do
+    {
+        unsigned long res, tmp;
+
+#ifdef CONFIG_ARM_32
+        asm volatile (" ldrex   %2, %1\n"
+                      " add     %2, %2, #1\n"
+                      " strex   %0, %2, %1\n"
+                      : "=&r" (res), "+Q" (mem), "=&r" (tmp));
+#else
+        asm volatile (" ldxr    %w2, %1\n"
+                      " add     %w2, %w2, #1\n"
+                      " stxr    %w0, %w2, %1\n"
+                      : "=&r" (res), "+Q" (mem), "=&r" (tmp));
+#endif
+        counter++;
+    } while (NOW() < deadline);
+
+    this_cpu(guest_safe_atomic_max) = counter;
+
+    printk(XENLOG_DEBUG
+           "CPU%u: Guest atomics will try %u times before pausing the domain\n",
+           smp_processor_id(), counter);
+}
+
+static int cpu_guest_safe_atomic_callback(struct notifier_block *nfb,
+                                          unsigned long action,
+                                          void *hcpu)
+{
+    if ( action == CPU_STARTING )
+        calibrate_safe_atomic();
+
+    return NOTIFY_DONE;
+}
+
+static struct notifier_block cpu_guest_safe_atomic_nfb = {
+    .notifier_call = cpu_guest_safe_atomic_callback,
+};
+
+static int __init guest_safe_atomic_init(void)
+{
+    register_cpu_notifier(&cpu_guest_safe_atomic_nfb);
+
+    calibrate_safe_atomic();
+
+    return 0;
+}
+presmp_initcall(guest_safe_atomic_init);
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-arm/guest_atomics.h b/xen/include/asm-arm/guest_atomics.h
new file mode 100644
index 0000000000..4f127fda41
--- /dev/null
+++ b/xen/include/asm-arm/guest_atomics.h
@@ -0,0 +1,76 @@
+#ifndef _ARM_GUEST_ATOMICS_H
+#define _ARM_GUEST_ATOMICS_H
+
+#include <xen/bitops.h>
+#include <xen/sched.h>
+
+/*
+ * The guest atomics helpers shares the same logic. We first try to use
+ * the *_timeout version of the operation. If it didn't timeout, then we
+ * successfully updated the memory. Nothing else to do.
+ *
+ * If it did timeout, then it means we didn't manage to update the
+ * memory. This is possibly because the guest is misbehaving (i.e tight
+ * store loop) but can also happen for other reasons (i.e nested Xen).
+ * In that case pause the domain and retry the operation, this time
+ * without a timeout.
+ *
+ * Note, those helpers rely on other part of the code to prevent sharing
+ * a page between Xen and multiple domain.
+ */
+
+DECLARE_PER_CPU(unsigned int, guest_safe_atomic_max);
+
+#define guest_bitop(name)                                                   \
+static inline void guest_##name(struct domain *d, int nr, volatile void *p) \
+{                                                                           \
+    if ( name##_timeout(nr, p, this_cpu(guest_safe_atomic_max)) )           \
+        return;                                                             \
+                                                                            \
+    domain_pause_nosync(d);                                                 \
+    name(nr, p);                                                            \
+    domain_unpause(d);                                                      \
+}
+
+#define guest_testop(name)                                                  \
+static inline int guest_##name(struct domain *d, int nr, volatile void *p)  \
+{                                                                           \
+    bool succeed;                                                           \
+    int oldbit;                                                             \
+                                                                            \
+    succeed = name##_timeout(nr, p, &oldbit,                                \
+                             this_cpu(guest_safe_atomic_max));              \
+    if ( succeed )                                                          \
+        return oldbit;                                                      \
+                                                                            \
+    domain_pause_nosync(d);                                                 \
+    oldbit = name(nr, p);                                                   \
+    domain_unpause(d);                                                      \
+                                                                            \
+    return oldbit;                                                          \
+}
+
+guest_bitop(set_bit)
+guest_bitop(clear_bit)
+guest_bitop(change_bit)
+
+#undef guest_bitop
+
+/* test_bit does not use load-store atomic operations */
+#define guest_test_bit(d, nr, p) ((void)(d), test_bit(nr, p))
+
+guest_testop(test_and_set_bit)
+guest_testop(test_and_clear_bit)
+guest_testop(test_and_change_bit)
+
+#undef guest_testop
+
+#endif /* _ARM_GUEST_ATOMICS_H */
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-x86/guest_atomics.h b/xen/include/asm-x86/guest_atomics.h
new file mode 100644
index 0000000000..0c71d2d278
--- /dev/null
+++ b/xen/include/asm-x86/guest_atomics.h
@@ -0,0 +1,30 @@
+#ifndef _X86_GUEST_ATOMICS_H
+#define _X86_GUEST_ATOMICS_H
+
+#include <xen/bitops.h>
+
+/*
+ * It is safe to use the atomics helpers on x86 on memory shared with
+ * the guests.
+ */
+#define guest_set_bit(d, nr, p)     ((void)(d), set_bit(nr, p))
+#define guest_clear_bit(d, nr, p)   ((void)(d), clear_bit(nr, p))
+#define guest_change_bit(d, nr, p)  ((void)(d), change_bit(nr, p))
+#define guest_test_bit(d, nr, p)    ((void)(d), test_bit(nr, p))
+
+#define guest_test_and_set_bit(d, nr, p)    \
+    ((void)(d), test_and_set_bit(nr, p))
+#define guest_test_and_clear_bit(d, nr, p)  \
+    ((void)(d), test_and_clear_bit(nr, p))
+#define guest_test_and_change_bit(d, nr, p) \
+    ((void)(d), test_and_change_bit(nr, p))
+
+#endif /* _X86_GUEST_ATOMICS_H */
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.17.1
xsa295/4.11-17.patch (application/octet-stream, 3.4 KB)
From d410b20098cfceb17eff3c12031e528542569197 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:27 +0100
Subject: [PATCH v2 4.11 17/20] xen/cmpxchg: Provide helper to safely modify
 guest memory atomically

On Arm, exclusive load-store atomics should only be used between trusted
thread. As not all the guests are trusted, it may be possible to DoS Xen
when updating shared memory with guest atomically.

This patch adds a new helper that will update the guest memory safely.
For x86, it is already possible to use the current helper safely. So
just wrap it.

For Arm, we will first attempt to update the guest memory with the
loop bounded by a maximum number of iterations. If it fails, we will
pause the domain and try again.

Note that this heuristics assumes that a page can only
be shared between Xen and one domain. Not Xen and multiple domain.

The maximum number of iterations is based on how many times atomic_inc()
can be executed in 1uS. The maximum value is per-CPU to cater big.LITTLE
and calculated when the CPU is booting.

The maximum number of iterations is based on how many times a simple
load-store atomic operation can be executed in 1uS. The maximum
value is per-CPU to cater big.LITTLE and calculated when the CPU is
booting. The heuristic was randomly chosen and can be modified if
impact too much good-behaving guest.

This is part of XSA-295.

Signed-of-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Acked-by: Jan Beulich <[email protected]>
---
 xen/include/asm-arm/guest_atomics.h | 25 +++++++++++++++++++++++++
 xen/include/asm-x86/guest_atomics.h |  2 ++
 2 files changed, 27 insertions(+)

diff --git a/xen/include/asm-arm/guest_atomics.h b/xen/include/asm-arm/guest_atomics.h
index 4f127fda41..61925d313d 100644
--- a/xen/include/asm-arm/guest_atomics.h
+++ b/xen/include/asm-arm/guest_atomics.h
@@ -65,6 +65,31 @@ guest_testop(test_and_change_bit)
 
 #undef guest_testop
 
+static inline unsigned long __guest_cmpxchg(struct domain *d,
+                                            volatile void *ptr,
+                                            unsigned long old,
+                                            unsigned long new,
+                                            unsigned int size)
+{
+    unsigned long oldval = old;
+
+    if ( __cmpxchg_mb_timeout(ptr, &oldval, new, size,
+                              this_cpu(guest_safe_atomic_max)) )
+        return oldval;
+
+    domain_pause_nosync(d);
+    oldval = __cmpxchg_mb(ptr, old, new, size);
+    domain_unpause(d);
+
+    return oldval;
+}
+
+#define guest_cmpxchg(d, ptr, o, n)                         \
+    ((__typeof__(*(ptr)))__guest_cmpxchg(d, ptr,            \
+                                         (unsigned long)(o),\
+                                         (unsigned long)(n),\
+                                         sizeof (*(ptr))))
+
 #endif /* _ARM_GUEST_ATOMICS_H */
 /*
  * Local variables:
diff --git a/xen/include/asm-x86/guest_atomics.h b/xen/include/asm-x86/guest_atomics.h
index 0c71d2d278..029417c8ff 100644
--- a/xen/include/asm-x86/guest_atomics.h
+++ b/xen/include/asm-x86/guest_atomics.h
@@ -19,6 +19,8 @@
 #define guest_test_and_change_bit(d, nr, p) \
     ((void)(d), test_and_change_bit(nr, p))
 
+#define guest_cmpxchg(d, ptr, o, n) ((void)(d), cmpxchg(ptr, o, n))
+
 #endif /* _X86_GUEST_ATOMICS_H */
 /*
  * Local variables:
-- 
2.17.1
xsa295/4.11-18.patch (application/octet-stream, 22.4 KB)
From 0689672212e95d65d2dd574c1fb620d3b88073cc Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:28 +0100
Subject: [PATCH v2 4.11 18/20] xen: Use guest atomics helpers when modifying
 atomically guest memory

On Arm, exclusive load-store atomics should only be used between trusted
thread. As not all the guests are trusted, it may be possible to DoS Xen
when updating shared memory with guest atomically.

This patch replaces all the atomics operations on shared memory with
a guest by the new guest atomics helpers. The x86 code was not audited
to know where guest atomics helpers could be used. I will leave that
to the x86 folks.

Note that some rework was required in order to plumb use the new guest
atomics in event channel and grant-table.

Because guest_test_bit is ignoring the parameter "d" for now, it
means there a lot of places do not need to drop the const. We may want
to revisit this in the future if the parameter "d" becomes necessary.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/domain.c             |  3 +-
 xen/arch/arm/mm.c                 |  6 ++--
 xen/common/event_2l.c             | 26 ++++++++------
 xen/common/event_fifo.c           | 44 ++++++++++++-----------
 xen/common/grant_table.c          | 59 +++++++++++++++++--------------
 xen/include/asm-arm/grant_table.h |  2 +-
 xen/include/asm-x86/grant_table.h |  3 +-
 7 files changed, 79 insertions(+), 64 deletions(-)

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index ec0f042bf7..112a146fd9 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -26,6 +26,7 @@
 #include <asm/event.h>
 #include <asm/gic.h>
 #include <asm/guest_access.h>
+#include <asm/guest_atomics.h>
 #include <asm/irq.h>
 #include <asm/p2m.h>
 #include <asm/platform.h>
@@ -961,7 +962,7 @@ void arch_dump_vcpu_info(struct vcpu *v)
 
 void vcpu_mark_events_pending(struct vcpu *v)
 {
-    int already_pending = test_and_set_bit(
+    bool already_pending = guest_test_and_set_bit(v->domain,
         0, (unsigned long *)&vcpu_info(v, evtchn_upcall_pending));
 
     if ( already_pending )
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index a6de77c28c..6b7e6b675b 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -40,6 +40,8 @@
 #include <xen/pfn.h>
 #include <xen/sizes.h>
 #include <xen/libfdt/libfdt.h>
+
+#include <asm/guest_atomics.h>
 #include <asm/setup.h>
 
 struct domain *dom_xen, *dom_io, *dom_cow;
@@ -1395,7 +1397,7 @@ void put_page_type(struct page_info *page)
     return;
 }
 
-void gnttab_clear_flag(unsigned long nr, uint16_t *addr)
+void gnttab_clear_flag(struct domain *d, unsigned long nr, uint16_t *addr)
 {
     /*
      * Note that this cannot be clear_bit(), as the access must be
@@ -1405,7 +1407,7 @@ void gnttab_clear_flag(unsigned long nr, uint16_t *addr)
 
     do {
         old = *addr;
-    } while (cmpxchg(addr, old, old & mask) != old);
+    } while (guest_cmpxchg(d, addr, old, old & mask) != old);
 }
 
 void gnttab_mark_dirty(struct domain *d, mfn_t mfn)
diff --git a/xen/common/event_2l.c b/xen/common/event_2l.c
index 8ca90899ab..e1dbb860f4 100644
--- a/xen/common/event_2l.c
+++ b/xen/common/event_2l.c
@@ -13,6 +13,8 @@
 #include <xen/sched.h>
 #include <xen/event.h>
 
+#include <asm/guest_atomics.h>
+
 static void evtchn_2l_set_pending(struct vcpu *v, struct evtchn *evtchn)
 {
     struct domain *d = v->domain;
@@ -25,12 +27,12 @@ static void evtchn_2l_set_pending(struct vcpu *v, struct evtchn *evtchn)
      * others may require explicit memory barriers.
      */
 
-    if ( test_and_set_bit(port, &shared_info(d, evtchn_pending)) )
+    if ( guest_test_and_set_bit(d, port, &shared_info(d, evtchn_pending)) )
         return;
 
-    if ( !test_bit        (port, &shared_info(d, evtchn_mask)) &&
-         !test_and_set_bit(port / BITS_PER_EVTCHN_WORD(d),
-                           &vcpu_info(v, evtchn_pending_sel)) )
+    if ( !guest_test_bit(d, port, &shared_info(d, evtchn_mask)) &&
+         !guest_test_and_set_bit(d, port / BITS_PER_EVTCHN_WORD(d),
+                                 &vcpu_info(v, evtchn_pending_sel)) )
     {
         vcpu_mark_events_pending(v);
     }
@@ -40,7 +42,7 @@ static void evtchn_2l_set_pending(struct vcpu *v, struct evtchn *evtchn)
 
 static void evtchn_2l_clear_pending(struct domain *d, struct evtchn *evtchn)
 {
-    clear_bit(evtchn->port, &shared_info(d, evtchn_pending));
+    guest_clear_bit(d, evtchn->port, &shared_info(d, evtchn_pending));
 }
 
 static void evtchn_2l_unmask(struct domain *d, struct evtchn *evtchn)
@@ -52,10 +54,10 @@ static void evtchn_2l_unmask(struct domain *d, struct evtchn *evtchn)
      * These operations must happen in strict order. Based on
      * evtchn_2l_set_pending() above.
      */
-    if ( test_and_clear_bit(port, &shared_info(d, evtchn_mask)) &&
-         test_bit          (port, &shared_info(d, evtchn_pending)) &&
-         !test_and_set_bit (port / BITS_PER_EVTCHN_WORD(d),
-                            &vcpu_info(v, evtchn_pending_sel)) )
+    if ( guest_test_and_clear_bit(d, port, &shared_info(d, evtchn_mask)) &&
+         guest_test_bit(d, port, &shared_info(d, evtchn_pending)) &&
+         !guest_test_and_set_bit(d, port / BITS_PER_EVTCHN_WORD(d),
+                                 &vcpu_info(v, evtchn_pending_sel)) )
     {
         vcpu_mark_events_pending(v);
     }
@@ -66,7 +68,8 @@ static bool evtchn_2l_is_pending(const struct domain *d, evtchn_port_t port)
     unsigned int max_ports = BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d);
 
     ASSERT(port < max_ports);
-    return port < max_ports && test_bit(port, &shared_info(d, evtchn_pending));
+    return (port < max_ports &&
+            guest_test_bit(d, port, &shared_info(d, evtchn_pending)));
 }
 
 static bool evtchn_2l_is_masked(const struct domain *d, evtchn_port_t port)
@@ -74,7 +77,8 @@ static bool evtchn_2l_is_masked(const struct domain *d, evtchn_port_t port)
     unsigned int max_ports = BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d);
 
     ASSERT(port < max_ports);
-    return port >= max_ports || test_bit(port, &shared_info(d, evtchn_mask));
+    return (port >= max_ports ||
+            guest_test_bit(d, port, &shared_info(d, evtchn_mask)));
 }
 
 static void evtchn_2l_print_state(struct domain *d,
diff --git a/xen/common/event_fifo.c b/xen/common/event_fifo.c
index c49f446754..3f4c835518 100644
--- a/xen/common/event_fifo.c
+++ b/xen/common/event_fifo.c
@@ -17,6 +17,8 @@
 #include <xen/mm.h>
 #include <xen/domain_page.h>
 
+#include <asm/guest_atomics.h>
+
 #include <public/event_channel.h>
 
 static inline event_word_t *evtchn_fifo_word_from_port(const struct domain *d,
@@ -50,7 +52,7 @@ static void evtchn_fifo_init(struct domain *d, struct evtchn *evtchn)
      * on the wrong VCPU or with an unexpected priority.
      */
     word = evtchn_fifo_word_from_port(d, evtchn->port);
-    if ( word && test_bit(EVTCHN_FIFO_LINKED, word) )
+    if ( word && guest_test_bit(d, EVTCHN_FIFO_LINKED, word) )
         gdprintk(XENLOG_WARNING, "domain %d, port %d already on a queue\n",
                  d->domain_id, evtchn->port);
 }
@@ -115,7 +117,7 @@ static int try_set_link(event_word_t *word, event_word_t *w, uint32_t link)
  * We block unmasking by the guest by marking the tail word as BUSY,
  * therefore, the cmpxchg() may fail at most 4 times.
  */
-static bool_t evtchn_fifo_set_link(const struct domain *d, event_word_t *word,
+static bool_t evtchn_fifo_set_link(struct domain *d, event_word_t *word,
                                    uint32_t link)
 {
     event_word_t w;
@@ -129,7 +131,7 @@ static bool_t evtchn_fifo_set_link(const struct domain *d, event_word_t *word,
         return ret;
 
     /* Lock the word to prevent guest unmasking. */
-    set_bit(EVTCHN_FIFO_BUSY, word);
+    guest_set_bit(d, EVTCHN_FIFO_BUSY, word);
 
     w = read_atomic(word);
 
@@ -139,13 +141,13 @@ static bool_t evtchn_fifo_set_link(const struct domain *d, event_word_t *word,
         if ( ret >= 0 )
         {
             if ( ret == 0 )
-                clear_bit(EVTCHN_FIFO_BUSY, word);
+                guest_clear_bit(d, EVTCHN_FIFO_BUSY, word);
             return ret;
         }
     }
     gdprintk(XENLOG_WARNING, "domain %d, port %d not linked\n",
              d->domain_id, link);
-    clear_bit(EVTCHN_FIFO_BUSY, word);
+    guest_clear_bit(d, EVTCHN_FIFO_BUSY, word);
     return 1;
 }
 
@@ -170,13 +172,13 @@ static void evtchn_fifo_set_pending(struct vcpu *v, struct evtchn *evtchn)
         return;
     }
 
-    was_pending = test_and_set_bit(EVTCHN_FIFO_PENDING, word);
+    was_pending = guest_test_and_set_bit(d, EVTCHN_FIFO_PENDING, word);
 
     /*
      * Link the event if it unmasked and not already linked.
      */
-    if ( !test_bit(EVTCHN_FIFO_MASKED, word)
-         && !test_bit(EVTCHN_FIFO_LINKED, word) )
+    if ( !guest_test_bit(d, EVTCHN_FIFO_MASKED, word) &&
+         !guest_test_bit(d, EVTCHN_FIFO_LINKED, word) )
     {
         struct evtchn_fifo_queue *q, *old_q;
         event_word_t *tail_word;
@@ -205,7 +207,7 @@ static void evtchn_fifo_set_pending(struct vcpu *v, struct evtchn *evtchn)
         if ( !old_q )
             goto done;
 
-        if ( test_and_set_bit(EVTCHN_FIFO_LINKED, word) )
+        if ( guest_test_and_set_bit(d, EVTCHN_FIFO_LINKED, word) )
         {
             spin_unlock_irqrestore(&old_q->lock, flags);
             goto done;
@@ -251,8 +253,8 @@ static void evtchn_fifo_set_pending(struct vcpu *v, struct evtchn *evtchn)
         spin_unlock_irqrestore(&q->lock, flags);
 
         if ( !linked
-             && !test_and_set_bit(q->priority,
-                                  &v->evtchn_fifo->control_block->ready) )
+             && !guest_test_and_set_bit(d, q->priority,
+                                        &v->evtchn_fifo->control_block->ready) )
             vcpu_mark_events_pending(v);
     }
  done:
@@ -274,7 +276,7 @@ static void evtchn_fifo_clear_pending(struct domain *d, struct evtchn *evtchn)
      * No need to unlink as the guest will unlink and ignore
      * non-pending events.
      */
-    clear_bit(EVTCHN_FIFO_PENDING, word);
+    guest_clear_bit(d, EVTCHN_FIFO_PENDING, word);
 }
 
 static void evtchn_fifo_unmask(struct domain *d, struct evtchn *evtchn)
@@ -286,10 +288,10 @@ static void evtchn_fifo_unmask(struct domain *d, struct evtchn *evtchn)
     if ( unlikely(!word) )
         return;
 
-    clear_bit(EVTCHN_FIFO_MASKED, word);
+    guest_clear_bit(d, EVTCHN_FIFO_MASKED, word);
 
     /* Relink if pending. */
-    if ( test_bit(EVTCHN_FIFO_PENDING, word) )
+    if ( guest_test_bit(d, EVTCHN_FIFO_PENDING, word) )
         evtchn_fifo_set_pending(v, evtchn);
 }
 
@@ -297,21 +299,21 @@ static bool evtchn_fifo_is_pending(const struct domain *d, evtchn_port_t port)
 {
     const event_word_t *word = evtchn_fifo_word_from_port(d, port);
 
-    return word && test_bit(EVTCHN_FIFO_PENDING, word);
+    return word && guest_test_bit(d, EVTCHN_FIFO_PENDING, word);
 }
 
 static bool_t evtchn_fifo_is_masked(const struct domain *d, evtchn_port_t port)
 {
     const event_word_t *word = evtchn_fifo_word_from_port(d, port);
 
-    return !word || test_bit(EVTCHN_FIFO_MASKED, word);
+    return !word || guest_test_bit(d, EVTCHN_FIFO_MASKED, word);
 }
 
 static bool_t evtchn_fifo_is_busy(const struct domain *d, evtchn_port_t port)
 {
     const event_word_t *word = evtchn_fifo_word_from_port(d, port);
 
-    return word && test_bit(EVTCHN_FIFO_LINKED, word);
+    return word && guest_test_bit(d, EVTCHN_FIFO_LINKED, word);
 }
 
 static int evtchn_fifo_set_priority(struct domain *d, struct evtchn *evtchn,
@@ -338,11 +340,11 @@ static void evtchn_fifo_print_state(struct domain *d,
     word = evtchn_fifo_word_from_port(d, evtchn->port);
     if ( !word )
         printk("?     ");
-    else if ( test_bit(EVTCHN_FIFO_LINKED, word) )
-        printk("%c %-4u", test_bit(EVTCHN_FIFO_BUSY, word) ? 'B' : ' ',
+    else if ( guest_test_bit(d, EVTCHN_FIFO_LINKED, word) )
+        printk("%c %-4u", guest_test_bit(d, EVTCHN_FIFO_BUSY, word) ? 'B' : ' ',
                *word & EVTCHN_FIFO_LINK_MASK);
     else
-        printk("%c -   ", test_bit(EVTCHN_FIFO_BUSY, word) ? 'B' : ' ');
+        printk("%c -   ", guest_test_bit(d, EVTCHN_FIFO_BUSY, word) ? 'B' : ' ');
 }
 
 static const struct evtchn_port_ops evtchn_port_ops_fifo =
@@ -494,7 +496,7 @@ static void setup_ports(struct domain *d)
 
         evtchn = evtchn_from_port(d, port);
 
-        if ( test_bit(port, &shared_info(d, evtchn_pending)) )
+        if ( guest_test_bit(d, port, &shared_info(d, evtchn_pending)) )
             evtchn->pending = 1;
 
         evtchn_fifo_set_priority(d, evtchn, EVTCHN_FIFO_PRIORITY_DEFAULT);
diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index c3a806fe47..221563a232 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -39,6 +39,7 @@
 #include <xen/vmap.h>
 #include <xsm/xsm.h>
 #include <asm/flushtlb.h>
+#include <asm/guest_atomics.h>
 
 /* Per-domain grant information. */
 struct grant_table {
@@ -653,6 +654,7 @@ static unsigned int nr_grant_entries(struct grant_table *gt)
 }
 
 static int _set_status_v1(const grant_entry_header_t *shah,
+                          struct domain *rd,
                           struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
@@ -708,8 +710,8 @@ static int _set_status_v1(const grant_entry_header_t *shah,
                          "Attempt to write-pin a r/o grant entry\n");
         }
 
-        prev_scombo.word = cmpxchg((u32 *)shah,
-                                   scombo.word, new_scombo.word);
+        prev_scombo.word = guest_cmpxchg(rd, (u32 *)shah,
+                                         scombo.word, new_scombo.word);
         if ( likely(prev_scombo.word == scombo.word) )
             break;
 
@@ -726,6 +728,7 @@ done:
 
 static int _set_status_v2(const grant_entry_header_t *shah,
                           grant_status_t *status,
+                          struct domain *rd,
                           struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
@@ -788,8 +791,8 @@ static int _set_status_v2(const grant_entry_header_t *shah,
              (id != ldomid) ||
              (!readonly && (flags & GTF_readonly)) )
         {
-            gnttab_clear_flag(_GTF_writing, status);
-            gnttab_clear_flag(_GTF_reading, status);
+            gnttab_clear_flag(rd, _GTF_writing, status);
+            gnttab_clear_flag(rd, _GTF_reading, status);
             PIN_FAIL(done, GNTST_general_error,
                      "Unstable flags (%x) or dom (%d); expected d%d (r/w: %d)\n",
                      flags, id, ldomid, !readonly);
@@ -799,7 +802,7 @@ static int _set_status_v2(const grant_entry_header_t *shah,
     {
         if ( unlikely(flags & GTF_readonly) )
         {
-            gnttab_clear_flag(_GTF_writing, status);
+            gnttab_clear_flag(rd, _GTF_writing, status);
             PIN_FAIL(done, GNTST_general_error,
                      "Unstable grant readonly flag\n");
         }
@@ -812,6 +815,7 @@ done:
 
 static int _set_status(const grant_entry_header_t *shah,
                        grant_status_t *status,
+                       struct domain *rd,
                        unsigned rgt_version,
                        struct active_grant_entry *act,
                        int readonly,
@@ -820,9 +824,9 @@ static int _set_status(const grant_entry_header_t *shah,
 {
 
     if ( rgt_version == 1 )
-        return _set_status_v1(shah, act, readonly, mapflag, ldomid);
+        return _set_status_v1(shah, rd, act, readonly, mapflag, ldomid);
     else
-        return _set_status_v2(shah, status, act, readonly, mapflag, ldomid);
+        return _set_status_v2(shah, status, rd, act, readonly, mapflag, ldomid);
 }
 
 static struct active_grant_entry *grant_map_exists(const struct domain *ld,
@@ -994,7 +998,7 @@ map_grant_ref(
          (!(op->flags & GNTMAP_readonly) &&
           !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask))) )
     {
-        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+        if ( (rc = _set_status(shah, status, rd, rgt->gt_version, act,
                                op->flags & GNTMAP_readonly, 1,
                                ld->domain_id) != GNTST_okay) )
             goto act_release_out;
@@ -1218,10 +1222,10 @@ map_grant_ref(
  unlock_out_clear:
     if ( !(op->flags & GNTMAP_readonly) &&
          !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) )
-        gnttab_clear_flag(_GTF_writing, status);
+        gnttab_clear_flag(rd, _GTF_writing, status);
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 
  act_release_out:
     active_entry_release(act);
@@ -1505,10 +1509,10 @@ unmap_common_complete(struct gnttab_unmap_common *op)
 
     if ( ((act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0) &&
          !(op->done & GNTMAP_readonly) )
-        gnttab_clear_flag(_GTF_writing, status);
+        gnttab_clear_flag(rd, _GTF_writing, status);
 
     if ( act->pin == 0 )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 
     active_entry_release(act);
     grant_read_unlock(rgt);
@@ -2073,8 +2077,8 @@ gnttab_prepare_for_transfer(
         new_scombo = scombo;
         new_scombo.shorts.flags |= GTF_transfer_committed;
 
-        prev_scombo.word = cmpxchg((u32 *)&sha->flags,
-                                   scombo.word, new_scombo.word);
+        prev_scombo.word = guest_cmpxchg(rd, (u32 *)&sha->flags,
+                                         scombo.word, new_scombo.word);
         if ( likely(prev_scombo.word == scombo.word) )
             break;
 
@@ -2359,11 +2363,11 @@ release_grant_for_copy(
 
         act->pin -= GNTPIN_hstw_inc;
         if ( !(act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) )
-            gnttab_clear_flag(_GTF_writing, status);
+            gnttab_clear_flag(rd, _GTF_writing, status);
     }
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 
     active_entry_release(act);
     grant_read_unlock(rgt);
@@ -2385,14 +2389,15 @@ release_grant_for_copy(
    under the domain's grant table lock. */
 /* Only safe on transitive grants.  Even then, note that we don't
    attempt to drop any pin on the referent grant. */
-static void fixup_status_for_copy_pin(const struct active_grant_entry *act,
+static void fixup_status_for_copy_pin(struct domain *rd,
+                                      const struct active_grant_entry *act,
                                       uint16_t *status)
 {
     if ( !(act->pin & (GNTPIN_hstw_mask | GNTPIN_devw_mask)) )
-        gnttab_clear_flag(_GTF_writing, status);
+        gnttab_clear_flag(rd, _GTF_writing, status);
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 }
 
 /* Grab a frame number from a grant entry and update the flags and pin
@@ -2452,7 +2457,7 @@ acquire_grant_for_copy(
     {
         if ( (!old_pin || (!readonly &&
                            !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)))) &&
-             (rc = _set_status_v2(shah, status, act, readonly, 0,
+             (rc = _set_status_v2(shah, status, rd, act, readonly, 0,
                                   ldom)) != GNTST_okay )
             goto unlock_out;
 
@@ -2501,7 +2506,7 @@ acquire_grant_for_copy(
 
         if ( rc != GNTST_okay )
         {
-            fixup_status_for_copy_pin(act, status);
+            fixup_status_for_copy_pin(rd, act, status);
             rcu_unlock_domain(td);
             active_entry_release(act);
             grant_read_unlock(rgt);
@@ -2524,7 +2529,7 @@ acquire_grant_for_copy(
                           !act->is_sub_page)) )
         {
             release_grant_for_copy(td, trans_gref, readonly);
-            fixup_status_for_copy_pin(act, status);
+            fixup_status_for_copy_pin(rd, act, status);
             rcu_unlock_domain(td);
             active_entry_release(act);
             grant_read_unlock(rgt);
@@ -2553,7 +2558,7 @@ acquire_grant_for_copy(
     else if ( !old_pin ||
               (!readonly && !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask))) )
     {
-        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+        if ( (rc = _set_status(shah, status, rd, rgt->gt_version, act,
                                readonly, 0, ldom)) != GNTST_okay )
              goto unlock_out;
 
@@ -2641,10 +2646,10 @@ acquire_grant_for_copy(
  unlock_out_clear:
     if ( !(readonly) &&
          !(act->pin & (GNTPIN_hstw_mask | GNTPIN_devw_mask)) )
-        gnttab_clear_flag(_GTF_writing, status);
+        gnttab_clear_flag(rd, _GTF_writing, status);
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 
  unlock_out:
     active_entry_release(act);
@@ -3712,11 +3717,11 @@ gnttab_release_mappings(
             }
 
             if ( (act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0 )
-                gnttab_clear_flag(_GTF_writing, status);
+                gnttab_clear_flag(rd, _GTF_writing, status);
         }
 
         if ( act->pin == 0 )
-            gnttab_clear_flag(_GTF_reading, status);
+            gnttab_clear_flag(rd, _GTF_reading, status);
 
         active_entry_release(act);
         grant_read_unlock(rgt);
diff --git a/xen/include/asm-arm/grant_table.h b/xen/include/asm-arm/grant_table.h
index 24958e4670..8ae8ba47a1 100644
--- a/xen/include/asm-arm/grant_table.h
+++ b/xen/include/asm-arm/grant_table.h
@@ -14,7 +14,7 @@ struct grant_table_arch {
     gfn_t *status_gfn;
 };
 
-void gnttab_clear_flag(unsigned long nr, uint16_t *addr);
+void gnttab_clear_flag(struct domain *d, unsigned long nr, uint16_t *addr);
 int create_grant_host_mapping(unsigned long gpaddr, mfn_t mfn,
                               unsigned int flags, unsigned int cache_flags);
 #define gnttab_host_mapping_get_page_type(ro, ld, rd) (0)
diff --git a/xen/include/asm-x86/grant_table.h b/xen/include/asm-x86/grant_table.h
index e42030936b..2a54fc8e1d 100644
--- a/xen/include/asm-x86/grant_table.h
+++ b/xen/include/asm-x86/grant_table.h
@@ -82,7 +82,8 @@ static inline unsigned int gnttab_dom0_max(void)
 
 #define gnttab_mark_dirty(d, f) paging_mark_dirty((d), f)
 
-static inline void gnttab_clear_flag(unsigned int nr, uint16_t *st)
+static inline void gnttab_clear_flag(struct domain *d, unsigned int nr,
+                                     uint16_t *st)
 {
     /*
      * Note that this cannot be clear_bit(), as the access must be
-- 
2.17.1
xsa295/4.11-19.patch (application/octet-stream, 4.1 KB)
From 2430cd0dfc21d595c2f5d9b98f41531ee0ca8f53 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:29 +0100
Subject: [PATCH v2 4.11 19/20] xen/arm: Add performance counters in guest
 atomic helpers

Add performance counters in guest atomic helpers to be able to detect
whether a guest is often paused during the operations.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Acked-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/guest_atomics.h | 12 ++++++++++++
 xen/include/asm-arm/perfc_defn.h    |  3 +++
 2 files changed, 15 insertions(+)

diff --git a/xen/include/asm-arm/guest_atomics.h b/xen/include/asm-arm/guest_atomics.h
index 61925d313d..698508bf87 100644
--- a/xen/include/asm-arm/guest_atomics.h
+++ b/xen/include/asm-arm/guest_atomics.h
@@ -24,9 +24,13 @@ DECLARE_PER_CPU(unsigned int, guest_safe_atomic_max);
 #define guest_bitop(name)                                                   \
 static inline void guest_##name(struct domain *d, int nr, volatile void *p) \
 {                                                                           \
+    perfc_incr(atomics_guest);                                              \
+                                                                            \
     if ( name##_timeout(nr, p, this_cpu(guest_safe_atomic_max)) )           \
         return;                                                             \
                                                                             \
+    perfc_incr(atomics_guest_paused);                                       \
+                                                                            \
     domain_pause_nosync(d);                                                 \
     name(nr, p);                                                            \
     domain_unpause(d);                                                      \
@@ -38,11 +42,15 @@ static inline int guest_##name(struct domain *d, int nr, volatile void *p)  \
     bool succeed;                                                           \
     int oldbit;                                                             \
                                                                             \
+    perfc_incr(atomics_guest);                                              \
+                                                                            \
     succeed = name##_timeout(nr, p, &oldbit,                                \
                              this_cpu(guest_safe_atomic_max));              \
     if ( succeed )                                                          \
         return oldbit;                                                      \
                                                                             \
+    perfc_incr(atomics_guest_paused);                                       \
+                                                                            \
     domain_pause_nosync(d);                                                 \
     oldbit = name(nr, p);                                                   \
     domain_unpause(d);                                                      \
@@ -73,10 +81,14 @@ static inline unsigned long __guest_cmpxchg(struct domain *d,
 {
     unsigned long oldval = old;
 
+    perfc_incr(atomics_guest);
+
     if ( __cmpxchg_mb_timeout(ptr, &oldval, new, size,
                               this_cpu(guest_safe_atomic_max)) )
         return oldval;
 
+    perfc_incr(atomics_guest_paused);
+
     domain_pause_nosync(d);
     oldval = __cmpxchg_mb(ptr, old, new, size);
     domain_unpause(d);
diff --git a/xen/include/asm-arm/perfc_defn.h b/xen/include/asm-arm/perfc_defn.h
index 8922e9525a..6a83185163 100644
--- a/xen/include/asm-arm/perfc_defn.h
+++ b/xen/include/asm-arm/perfc_defn.h
@@ -73,6 +73,9 @@ PERFCOUNTER(phys_timer_irqs,  "Physical timer interrupts")
 PERFCOUNTER(virt_timer_irqs,  "Virtual timer interrupts")
 PERFCOUNTER(maintenance_irqs, "Maintenance interrupts")
 
+PERFCOUNTER(atomics_guest,    "atomics: guest access")
+PERFCOUNTER(atomics_guest_paused,   "atomics: guest paused")
+
 /*#endif*/ /* __XEN_PERFC_DEFN_H__ */
 
 /*
-- 
2.17.1
xsa295/4.11-20.patch (application/octet-stream, 6.4 KB)
From 9294c354e1830be750177ed4e5f3f693aba08de3 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:30 +0100
Subject: [PATCH v2 4.11 20/20] xen/arm: grant-table: Protect gnttab_clear_flag
 against guest misbehavior

The function gnttab_clear_flag is used to clear the access flags. On
Arm, it is implemented using a loop and guest_cmpxchg.

It is possible that guest_cmpxchg will always return a different value
than old. This can happen if the guest updated the memory before Xen has
time to do the exchange. Because of that, there are no way for to
promise the loop will end.

It is possible to make the current code safe by re-using the same
principle as applied on the guest atomic helper. However this patch
takes a different approach that should lead to more efficient code in
the default case.

A new helper is introduced to clear a set of bits on a 16-bits word.
This should avoid a an extra loop to check cmpxchg succeeded.

Note that a mask is used instead of a bit, so the helper can be re-used
later on for clearing multiple flags at the same time.

This is part of XSA-295.

Reported-by: Andrew Cooper <[email protected]>
Signed-off-by: Julien Grall <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/arm32/lib/bitops.c     | 35 +++++++++++++++++++++++++++++
 xen/arch/arm/arm64/lib/bitops.c     | 33 +++++++++++++++++++++++++++
 xen/arch/arm/mm.c                   | 10 +--------
 xen/include/asm-arm/bitops.h        |  4 ++++
 xen/include/asm-arm/guest_atomics.h | 13 +++++++++++
 5 files changed, 86 insertions(+), 9 deletions(-)

diff --git a/xen/arch/arm/arm32/lib/bitops.c b/xen/arch/arm/arm32/lib/bitops.c
index 08750314fc..3dca769bf0 100644
--- a/xen/arch/arm/arm32/lib/bitops.c
+++ b/xen/arch/arm/arm32/lib/bitops.c
@@ -126,6 +126,41 @@ testop(test_and_change_bit, eor)
 testop(test_and_clear_bit, bic)
 testop(test_and_set_bit, orr)
 
+static always_inline bool int_clear_mask16(uint16_t mask, volatile uint16_t *p,
+                                           bool timeout, unsigned int max_try)
+{
+    unsigned long res, tmp;
+
+    prefetchw((const uint16_t *)p);
+
+    do
+    {
+        asm volatile ("// int_clear_mask16\n"
+        "   ldrexh  %2, %1\n"
+        "   bic     %2, %2, %3\n"
+        "   strexh  %0, %2, %1\n"
+        : "=&r" (res), "+Qo" (*p), "=&r" (tmp)
+        : "r" (mask));
+
+        if ( !res )
+            break;
+    } while ( !timeout || ((--max_try) > 0) );
+
+    return !res;
+}
+
+void clear_mask16(uint16_t mask, volatile void *p)
+{
+    if ( !int_clear_mask16(mask, p, false, 0) )
+        ASSERT_UNREACHABLE();
+}
+
+bool clear_mask16_timeout(uint16_t mask, volatile void *p,
+                          unsigned int max_try)
+{
+    return int_clear_mask16(mask, p, true, max_try);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
index 78bf4ed8c5..27688e5418 100644
--- a/xen/arch/arm/arm64/lib/bitops.c
+++ b/xen/arch/arm/arm64/lib/bitops.c
@@ -118,6 +118,39 @@ testop(test_and_change_bit, eor)
 testop(test_and_clear_bit, bic)
 testop(test_and_set_bit, orr)
 
+static always_inline bool int_clear_mask16(uint16_t mask, volatile uint16_t *p,
+                                           bool timeout, unsigned int max_try)
+{
+    unsigned long res, tmp;
+
+    do
+    {
+        asm volatile ("//  int_clear_mask16\n"
+        "   ldxrh   %w2, %1\n"
+        "   bic     %w2, %w2, %w3\n"
+        "   stxrh   %w0, %w2, %1\n"
+        : "=&r" (res), "+Q" (*p), "=&r" (tmp)
+        : "r" (mask));
+
+        if ( !res )
+            break;
+    } while ( !timeout || ((--max_try) > 0) );
+
+    return !res;
+}
+
+void clear_mask16(uint16_t mask, volatile void *p)
+{
+    if ( !int_clear_mask16(mask, p, false, 0) )
+        ASSERT_UNREACHABLE();
+}
+
+bool clear_mask16_timeout(uint16_t mask, volatile void *p,
+                          unsigned int max_try)
+{
+    return int_clear_mask16(mask, p, true, max_try);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 6b7e6b675b..2b4d5ed091 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -1399,15 +1399,7 @@ void put_page_type(struct page_info *page)
 
 void gnttab_clear_flag(struct domain *d, unsigned long nr, uint16_t *addr)
 {
-    /*
-     * Note that this cannot be clear_bit(), as the access must be
-     * confined to the specified 2 bytes.
-     */
-    uint16_t mask = ~(1 << nr), old;
-
-    do {
-        old = *addr;
-    } while (guest_cmpxchg(d, addr, old, old & mask) != old);
+    guest_clear_mask16(d, BIT(nr), addr);
 }
 
 void gnttab_mark_dirty(struct domain *d, mfn_t mfn)
diff --git a/xen/include/asm-arm/bitops.h b/xen/include/asm-arm/bitops.h
index f6782b33be..f989bc726c 100644
--- a/xen/include/asm-arm/bitops.h
+++ b/xen/include/asm-arm/bitops.h
@@ -53,6 +53,8 @@ int test_and_set_bit(int nr, volatile void *p);
 int test_and_clear_bit(int nr, volatile void *p);
 int test_and_change_bit(int nr, volatile void *p);
 
+void clear_mask16(uint16_t mask, volatile void *p);
+
 /*
  * The helpers below may fail to update the memory if the action takes
  * too long.
@@ -71,6 +73,8 @@ bool test_and_clear_bit_timeout(int nr, volatile void *p,
                                 int *oldbit, unsigned int max_try);
 bool test_and_change_bit_timeout(int nr, volatile void *p,
                                  int *oldbit, unsigned int max_try);
+bool clear_mask16_timeout(uint16_t mask, volatile void *p,
+                          unsigned int max_try);
 
 /**
  * __test_and_set_bit - Set a bit and return its old value
diff --git a/xen/include/asm-arm/guest_atomics.h b/xen/include/asm-arm/guest_atomics.h
index 698508bf87..af27cc627b 100644
--- a/xen/include/asm-arm/guest_atomics.h
+++ b/xen/include/asm-arm/guest_atomics.h
@@ -73,6 +73,19 @@ guest_testop(test_and_change_bit)
 
 #undef guest_testop
 
+static inline void guest_clear_mask16(struct domain *d, uint16_t mask,
+                                      volatile uint16_t *p)
+{
+    perfc_incr(atomics_guest);
+
+    if ( clear_mask16_timeout(mask, p, this_cpu(guest_safe_atomic_max)) )
+        return;
+
+    domain_pause_nosync(d);
+    clear_mask16(mask, p);
+    domain_unpause(d);
+}
+
 static inline unsigned long __guest_cmpxchg(struct domain *d,
                                             volatile void *ptr,
                                             unsigned long old,
-- 
2.17.1
xsa295/4.12-01.patch (application/octet-stream, 3 KB)
From 00617d5cc62d2bf4d02493aeafad14cca4e09a66 Mon Sep 17 00:00:00 2001
From: Jan Beulich <[email protected]>
Date: Tue, 12 Mar 2019 14:40:24 +0100
Subject: [PATCH v2 4.12 01/17] events: drop arch_evtchn_inject()

Have the only user call vcpu_mark_events_pending() instead, at the same
time arranging for correct ordering of the writes (evtchn_pending_sel
should be written before evtchn_upcall_pending).

Signed-off-by: Jan Beulich <[email protected]>
Reviewed-by: Andrew Cooper <[email protected]>
Reviewed-by: Julien Grall <[email protected]>
---
 xen/arch/arm/vgic.c      | 5 -----
 xen/arch/arm/vgic/vgic.c | 5 -----
 xen/arch/x86/irq.c       | 6 ------
 xen/common/domain.c      | 3 +--
 xen/include/xen/event.h  | 3 ---
 5 files changed, 1 insertion(+), 21 deletions(-)

diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index f2608b042d..19d8c9b876 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -597,11 +597,6 @@ out:
     return;
 }
 
-void arch_evtchn_inject(struct vcpu *v)
-{
-    vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, true);
-}
-
 bool vgic_evtchn_irq_pending(struct vcpu *v)
 {
     struct pending_irq *p;
diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index e2844dcc20..f0f2ea5021 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -692,11 +692,6 @@ void vgic_kick_vcpus(struct domain *d)
     }
 }
 
-void arch_evtchn_inject(struct vcpu *v)
-{
-    vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, true);
-}
-
 bool vgic_evtchn_irq_pending(struct vcpu *v)
 {
     struct vgic_irq *irq;
diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c
index 23b4f423e6..8511953977 100644
--- a/xen/arch/x86/irq.c
+++ b/xen/arch/x86/irq.c
@@ -2724,9 +2724,3 @@ int allocate_and_map_msi_pirq(struct domain *d, int index, int *pirq_p,
 
     return ret;
 }
-
-void arch_evtchn_inject(struct vcpu *v)
-{
-    if ( is_hvm_vcpu(v) )
-        hvm_assert_evtchn_irq(v);
-}
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 32bca8dbf2..0542338862 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -1306,10 +1306,9 @@ int map_vcpu_info(struct vcpu *v, unsigned long gfn, unsigned offset)
      * Mark everything as being pending just to make sure nothing gets
      * lost.  The domain will get a spurious event, but it can cope.
      */
-    vcpu_info(v, evtchn_upcall_pending) = 1;
     for ( i = 0; i < BITS_PER_EVTCHN_WORD(d); i++ )
         set_bit(i, &vcpu_info(v, evtchn_pending_sel));
-    arch_evtchn_inject(v);
+    vcpu_mark_events_pending(v);
 
     return 0;
 }
diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h
index e91097d77e..a7798f6765 100644
--- a/xen/include/xen/event.h
+++ b/xen/include/xen/event.h
@@ -91,9 +91,6 @@ int guest_enabled_event(struct vcpu *v, uint32_t virq);
 /* Notify remote end of a Xen-attached event channel.*/
 void notify_via_xen_event_channel(struct domain *ld, int lport);
 
-/* Inject an event channel notification into the guest */
-void arch_evtchn_inject(struct vcpu *v);
-
 /*
  * Internal event channel object storage.
  *
-- 
2.17.1
xsa295/4.12-02.patch (application/octet-stream, 3.7 KB)
From 8908fe0d3f42a4764d29e6aa657749d7a1b4c8ca Mon Sep 17 00:00:00 2001
From: Jan Beulich <[email protected]>
Date: Tue, 12 Mar 2019 14:40:56 +0100
Subject: [PATCH v2 4.12 02/17] common: avoid atomic read-modify-write accesses
 in map_vcpu_info()

There's no need to set the evtchn_pending_sel bits one by one. Simply
write full words with all ones.

For Arm this requires extending write_atomic() to also handle 64-bit
values; for symmetry read_atomic() gets adjusted as well.

Signed-off-by: Jan Beulich <[email protected]>
Reviewed-by: Andrew Cooper <[email protected]>
Reviewed-by: Julien Grall <[email protected]>
---
 xen/common/domain.c          |  9 ++++++---
 xen/include/asm-arm/atomic.h | 15 +++++++++++++++
 2 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/xen/common/domain.c b/xen/common/domain.c
index 0542338862..3b18f11f12 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -1253,7 +1253,6 @@ int map_vcpu_info(struct vcpu *v, unsigned long gfn, unsigned offset)
     void *mapping;
     vcpu_info_t *new_info;
     struct page_info *page;
-    int i;
 
     if ( offset > (PAGE_SIZE - sizeof(vcpu_info_t)) )
         return -EINVAL;
@@ -1306,8 +1305,12 @@ int map_vcpu_info(struct vcpu *v, unsigned long gfn, unsigned offset)
      * Mark everything as being pending just to make sure nothing gets
      * lost.  The domain will get a spurious event, but it can cope.
      */
-    for ( i = 0; i < BITS_PER_EVTCHN_WORD(d); i++ )
-        set_bit(i, &vcpu_info(v, evtchn_pending_sel));
+#ifdef CONFIG_COMPAT
+    if ( !has_32bit_shinfo(d) )
+        write_atomic(&new_info->native.evtchn_pending_sel, ~0);
+    else
+#endif
+        write_atomic(&vcpu_info(v, evtchn_pending_sel), ~0);
     vcpu_mark_events_pending(v);
 
     return 0;
diff --git a/xen/include/asm-arm/atomic.h b/xen/include/asm-arm/atomic.h
index afb3eeea5b..7b4c987fa7 100644
--- a/xen/include/asm-arm/atomic.h
+++ b/xen/include/asm-arm/atomic.h
@@ -55,6 +55,19 @@ build_atomic_write(write_int_atomic, "",  WORD, int, "r")
 #if defined (CONFIG_ARM_64)
 build_atomic_read(read_u64_atomic, "", "", uint64_t, "=r")
 build_atomic_write(write_u64_atomic, "", "", uint64_t, "r")
+#elif defined (CONFIG_ARM_32)
+static inline uint64_t read_u64_atomic(const volatile uint64_t *addr)
+{
+    uint64_t val;
+
+    asm volatile ( "ldrd %0,%H0,%1" : "=r" (val) : "m" (*addr) );
+
+    return val;
+}
+static inline void write_u64_atomic(volatile uint64_t *addr, uint64_t val)
+{
+    asm volatile ( "strd %1,%H1,%0" : "=m" (*addr) : "r" (val) );
+}
 #endif
 
 build_add_sized(add_u8_sized, "b", BYTE, uint8_t, "ri")
@@ -69,6 +82,7 @@ void __bad_atomic_size(void);
     case 1: __x = (typeof(*p))read_u8_atomic((uint8_t *)p); break;      \
     case 2: __x = (typeof(*p))read_u16_atomic((uint16_t *)p); break;    \
     case 4: __x = (typeof(*p))read_u32_atomic((uint32_t *)p); break;    \
+    case 8: __x = (typeof(*p))read_u64_atomic((uint64_t *)p); break;    \
     default: __x = 0; __bad_atomic_size(); break;                       \
     }                                                                   \
     __x;                                                                \
@@ -80,6 +94,7 @@ void __bad_atomic_size(void);
     case 1: write_u8_atomic((uint8_t *)p, (uint8_t)__x); break;         \
     case 2: write_u16_atomic((uint16_t *)p, (uint16_t)__x); break;      \
     case 4: write_u32_atomic((uint32_t *)p, (uint32_t)__x); break;      \
+    case 8: write_u64_atomic((uint64_t *)p, (uint64_t)__x); break;      \
     default: __bad_atomic_size(); break;                                \
     }                                                                   \
     __x;                                                                \
-- 
2.17.1
xsa295/4.12-03.patch (application/octet-stream, 2 KB)
From bbe4ec0187f66c8afc0a4c55bb94e7ccd4ce68a5 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:16 +0100
Subject: [PATCH v2 4.12 03/17] xen/arm: Add an isb() before reading CNTPCT_EL0
 to prevent re-ordering

Per D8.2.1 in ARM DDI 0487C.a, "a read to CNTPCT_EL0 can occur
speculatively and out of order relative to other instructions executed
on the same PE."

Add an instruction barrier to get accurate number of cycles when
requested in get_cycles(). For the other users of CNPCT_EL0, replace by
a call to get_cycles().

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Acked-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/time.c        | 4 ++--
 xen/include/asm-arm/time.h | 2 ++
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/time.c b/xen/arch/arm/time.c
index bbccee742e..739bcf186c 100644
--- a/xen/arch/arm/time.c
+++ b/xen/arch/arm/time.c
@@ -151,7 +151,7 @@ void __init preinit_xen_time(void)
     if ( res )
         panic("Timer: Cannot initialize platform timer\n");
 
-    boot_count = READ_SYSREG64(CNTPCT_EL0);
+    boot_count = get_cycles();
 }
 
 static void __init init_dt_xen_time(void)
@@ -192,7 +192,7 @@ int __init init_xen_time(void)
 /* Return number of nanoseconds since boot */
 s_time_t get_s_time(void)
 {
-    uint64_t ticks = READ_SYSREG64(CNTPCT_EL0) - boot_count;
+    uint64_t ticks = get_cycles() - boot_count;
     return ticks_to_ns(ticks);
 }
 
diff --git a/xen/include/asm-arm/time.h b/xen/include/asm-arm/time.h
index 9a7071a546..9cb6f9b0b4 100644
--- a/xen/include/asm-arm/time.h
+++ b/xen/include/asm-arm/time.h
@@ -2,6 +2,7 @@
 #define __ARM_TIME_H__
 
 #include <asm/sysregs.h>
+#include <asm/system.h>
 
 #define DT_MATCH_TIMER                      \
     DT_MATCH_COMPATIBLE("arm,armv7-timer"), \
@@ -11,6 +12,7 @@ typedef uint64_t cycles_t;
 
 static inline cycles_t get_cycles (void)
 {
+        isb();
         return READ_SYSREG64(CNTPCT_EL0);
 }
 
-- 
2.17.1
xsa295/4.12-04.patch (application/octet-stream, 6.6 KB)
From d0020117111a77eeee7db6ef52ff87347c8c54b7 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:17 +0100
Subject: [PATCH v2 4.12 04/17] xen/grant_table: Rework the prototype of
 _set_status* for lisibility

It is not clear from the parameters name whether domid and gt_version
correspond to the local or remote domain. A follow-up patch will make
them more confusing.

So rename domid (resp. gt_version) to ldomid (resp. rgt_version). At
the same time re-order the parameters to hopefully make it more
readable.

This is part of XSA-295.

Suggested-by: Jan Beulich <[email protected]>
Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Jan Beulich <[email protected]>
Acked-by: Stefano Stabellini <[email protected]>
---
 xen/common/grant_table.c | 57 ++++++++++++++++++++--------------------
 1 file changed, 28 insertions(+), 29 deletions(-)

diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index 80728ea57d..1b82d534a3 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -645,11 +645,11 @@ static unsigned int nr_grant_entries(struct grant_table *gt)
     return 0;
 }
 
-static int _set_status_v1(domid_t  domid,
+static int _set_status_v1(const grant_entry_header_t *shah,
+                          struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
-                          grant_entry_header_t *shah,
-                          struct active_grant_entry *act)
+                          domid_t  ldomid)
 {
     int rc = GNTST_okay;
     union grant_combo scombo, prev_scombo, new_scombo;
@@ -684,11 +684,11 @@ static int _set_status_v1(domid_t  domid,
         if ( !act->pin &&
              (((scombo.shorts.flags & mask) !=
                GTF_permit_access) ||
-              (scombo.shorts.domid != domid)) )
+              (scombo.shorts.domid != ldomid)) )
             PIN_FAIL(done, GNTST_general_error,
                      "Bad flags (%x) or dom (%d); expected d%d\n",
                      scombo.shorts.flags, scombo.shorts.domid,
-                     domid);
+                     ldomid);
 
         new_scombo = scombo;
         new_scombo.shorts.flags |= GTF_reading;
@@ -717,12 +717,12 @@ done:
     return rc;
 }
 
-static int _set_status_v2(domid_t  domid,
+static int _set_status_v2(const grant_entry_header_t *shah,
+                          grant_status_t *status,
+                          struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
-                          grant_entry_header_t *shah,
-                          struct active_grant_entry *act,
-                          grant_status_t *status)
+                          domid_t  ldomid)
 {
     int      rc    = GNTST_okay;
     union grant_combo scombo;
@@ -748,10 +748,10 @@ static int _set_status_v2(domid_t  domid,
     if ( !act->pin &&
          ( (((flags & mask) != GTF_permit_access) &&
             ((flags & mask) != GTF_transitive)) ||
-          (id != domid)) )
+          (id != ldomid)) )
         PIN_FAIL(done, GNTST_general_error,
                  "Bad flags (%x) or dom (%d); expected d%d, flags %x\n",
-                 flags, id, domid, mask);
+                 flags, id, ldomid, mask);
 
     if ( readonly )
     {
@@ -778,14 +778,14 @@ static int _set_status_v2(domid_t  domid,
     {
         if ( (((flags & mask) != GTF_permit_access) &&
               ((flags & mask) != GTF_transitive)) ||
-             (id != domid) ||
+             (id != ldomid) ||
              (!readonly && (flags & GTF_readonly)) )
         {
             gnttab_clear_flag(_GTF_writing, status);
             gnttab_clear_flag(_GTF_reading, status);
             PIN_FAIL(done, GNTST_general_error,
                      "Unstable flags (%x) or dom (%d); expected d%d (r/w: %d)\n",
-                     flags, id, domid, !readonly);
+                     flags, id, ldomid, !readonly);
         }
     }
     else
@@ -803,19 +803,19 @@ done:
 }
 
 
-static int _set_status(unsigned gt_version,
-                       domid_t  domid,
+static int _set_status(const grant_entry_header_t *shah,
+                       grant_status_t *status,
+                       unsigned rgt_version,
+                       struct active_grant_entry *act,
                        int readonly,
                        int mapflag,
-                       grant_entry_header_t *shah,
-                       struct active_grant_entry *act,
-                       grant_status_t *status)
+                       domid_t ldomid)
 {
 
-    if ( gt_version == 1 )
-        return _set_status_v1(domid, readonly, mapflag, shah, act);
+    if ( rgt_version == 1 )
+        return _set_status_v1(shah, act, readonly, mapflag, ldomid);
     else
-        return _set_status_v2(domid, readonly, mapflag, shah, act, status);
+        return _set_status_v2(shah, status, act, readonly, mapflag, ldomid);
 }
 
 static struct active_grant_entry *grant_map_exists(const struct domain *ld,
@@ -980,9 +980,9 @@ map_grant_ref(
          (!(op->flags & GNTMAP_readonly) &&
           !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask))) )
     {
-        if ( (rc = _set_status(rgt->gt_version, ld->domain_id,
-                               op->flags & GNTMAP_readonly,
-                               1, shah, act, status) ) != GNTST_okay )
+        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+                               op->flags & GNTMAP_readonly, 1,
+                               ld->domain_id) != GNTST_okay) )
             goto act_release_out;
 
         if ( !act->pin )
@@ -2434,8 +2434,8 @@ acquire_grant_for_copy(
     {
         if ( (!old_pin || (!readonly &&
                            !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)))) &&
-             (rc = _set_status_v2(ldom, readonly, 0, shah, act,
-                                  status)) != GNTST_okay )
+             (rc = _set_status_v2(shah, status, act, readonly, 0,
+                                  ldom)) != GNTST_okay )
             goto unlock_out;
 
         if ( !allow_transitive )
@@ -2535,9 +2535,8 @@ acquire_grant_for_copy(
     else if ( !old_pin ||
               (!readonly && !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask))) )
     {
-        if ( (rc = _set_status(rgt->gt_version, ldom,
-                               readonly, 0, shah, act,
-                               status) ) != GNTST_okay )
+        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+                               readonly, 0, ldom)) != GNTST_okay )
              goto unlock_out;
 
         td = rd;
-- 
2.17.1
xsa295/4.12-05.patch (application/octet-stream, 7.8 KB)
From e40140db5da810c4ead632ae5d346558f2b93695 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:18 +0100
Subject: [PATCH v2 4.12 05/17] xen/arm64: bitops: Rewrite bitop helpers in C

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/README.LinuxPrimitives |  1 -
 xen/arch/arm/arm64/lib/bitops.S     | 67 ---------------------
 xen/arch/arm/arm64/lib/bitops.c     | 90 +++++++++++++++++++++++++++++
 3 files changed, 90 insertions(+), 68 deletions(-)
 delete mode 100644 xen/arch/arm/arm64/lib/bitops.S
 create mode 100644 xen/arch/arm/arm64/lib/bitops.c

diff --git a/xen/arch/arm/README.LinuxPrimitives b/xen/arch/arm/README.LinuxPrimitives
index 028e8721f9..891667a5da 100644
--- a/xen/arch/arm/README.LinuxPrimitives
+++ b/xen/arch/arm/README.LinuxPrimitives
@@ -8,7 +8,6 @@ arm64:
 
 bitops: last sync @ v3.16-rc6 (last commit: 8715466b6027)
 
-linux/arch/arm64/lib/bitops.S           xen/arch/arm/arm64/lib/bitops.S
 linux/arch/arm64/include/asm/bitops.h   xen/include/asm-arm/arm64/bitops.h
 
 ---------------------------------------------------------------------
diff --git a/xen/arch/arm/arm64/lib/bitops.S b/xen/arch/arm/arm64/lib/bitops.S
deleted file mode 100644
index 6471dd1875..0000000000
--- a/xen/arch/arm/arm64/lib/bitops.S
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Based on linux/arch/arm64/lib/bitops.h which in turn is
- * Based on arch/arm/lib/bitops.h
- *
- * Copyright (C) 2013 ARM Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * x0: bits 4:0  bit offset
- *     bits 31:5 word offset
- * x1: address
- */
-	.macro	bitop, name, instr
-ENTRY(	\name	)
-	and	w3, w0, #31		// Get bit offset
-	eor	w0, w0, w3		// Clear low bits
-	mov	x2, #1
-	add	x1, x1, x0, lsr #3	// Get word offset
-	lsl	x3, x2, x3		// Create mask
-1:	ldxr	w2, [x1]
-	\instr	w2, w2, w3
-	stxr	w0, w2, [x1]
-	cbnz	w0, 1b
-	ret
-ENDPROC(\name	)
-	.endm
-
-	.macro	testop, name, instr
-ENTRY(	\name	)
-	and	w3, w0, #31		// Get bit offset
-	eor	w0, w0, w3		// Clear low bits
-	mov	x2, #1
-	add	x1, x1, x0, lsr #3	// Get word offset
-	lsl	x4, x2, x3		// Create mask
-1:	ldxr	w2, [x1]
-	lsr	w0, w2, w3		// Save old value of bit
-	\instr	w2, w2, w4		// toggle bit
-	stlxr	w5, w2, [x1]
-	cbnz	w5, 1b
-	dmb	ish
-	and	w0, w0, #1
-3:	ret
-ENDPROC(\name	)
-	.endm
-
-/*
- * Atomic bit operations.
- */
-	bitop	change_bit, eor
-	bitop	clear_bit, bic
-	bitop	set_bit, orr
-
-	testop	test_and_change_bit, eor
-	testop	test_and_clear_bit, bic
-	testop	test_and_set_bit, orr
diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
new file mode 100644
index 0000000000..b1c681c642
--- /dev/null
+++ b/xen/arch/arm/arm64/lib/bitops.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/bitops.h>
+#include <asm/system.h>
+
+/*
+ * The atomic bit operations pass the number of bit in a signed number
+ * (not sure why). This has the drawback to increase the complexity of
+ * the resulting assembly.
+ *
+ * To generate simpler code, the number of bit (nr) will be cast to
+ * unsigned int.
+ *
+ * XXX: Rework the interface to use unsigned int.
+ */
+
+#define bitop(name, instr)                                                  \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
+    unsigned long res, tmp;                                                 \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldxr    %w2, %1\n"                                              \
+        "   " __stringify(instr) "     %w2, %w2, %w3\n"                     \
+        "   stxr    %w0, %w2, %1\n"                                         \
+        : "=&r" (res), "+Q" (*ptr), "=&r" (tmp)                             \
+        : "r" (mask));                                                      \
+    } while ( res );                                                        \
+}                                                                           \
+
+#define testop(name, instr)                                                 \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
+    const uint32_t mask = BIT_MASK(bit);                                    \
+    unsigned long res, tmp;                                                 \
+    unsigned long oldbit;                                                   \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldxr    %w3, %2\n"                                              \
+        "   lsr     %w1, %w3, %w5 // Save old value of bit\n"               \
+        "   " __stringify(instr) "  %w3, %w3, %w4 // Toggle bit\n"          \
+        "   stlxr   %w0, %w3, %2\n"                                         \
+        : "=&r" (res), "=&r" (oldbit), "+Q" (*ptr), "=&r" (tmp)             \
+        : "r" (mask), "r" (bit)                                             \
+        : "memory");                                                        \
+    } while ( res );                                                        \
+                                                                            \
+    dmb(ish);                                                               \
+                                                                            \
+    return oldbit & 1;                                                      \
+}
+
+bitop(change_bit, eor)
+bitop(clear_bit, bic)
+bitop(set_bit, orr)
+
+testop(test_and_change_bit, eor)
+testop(test_and_clear_bit, bic)
+testop(test_and_set_bit, orr)
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.17.1
xsa295/4.12-06.patch (application/octet-stream, 15.5 KB)
From b919e89a3cc3295ee56b1392d42ba7eea898f9d4 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:19 +0100
Subject: [PATCH v2 4.12 06/17] xen/arm32: bitops: Rewrite bitop helpers in C

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/README.LinuxPrimitives    |  14 +---
 xen/arch/arm/arm32/lib/Makefile        |   5 +-
 xen/arch/arm/arm32/lib/bitops.c        |  98 +++++++++++++++++++++++
 xen/arch/arm/arm32/lib/bitops.h        | 104 -------------------------
 xen/arch/arm/arm32/lib/changebit.S     |  14 ----
 xen/arch/arm/arm32/lib/clearbit.S      |  14 ----
 xen/arch/arm/arm32/lib/setbit.S        |  15 ----
 xen/arch/arm/arm32/lib/testchangebit.S |  15 ----
 xen/arch/arm/arm32/lib/testclearbit.S  |  15 ----
 xen/arch/arm/arm32/lib/testsetbit.S    |  15 ----
 xen/include/asm-arm/arm32/bitops.h     |  19 ++---
 11 files changed, 108 insertions(+), 220 deletions(-)
 create mode 100644 xen/arch/arm/arm32/lib/bitops.c
 delete mode 100644 xen/arch/arm/arm32/lib/bitops.h
 delete mode 100644 xen/arch/arm/arm32/lib/changebit.S
 delete mode 100644 xen/arch/arm/arm32/lib/clearbit.S
 delete mode 100644 xen/arch/arm/arm32/lib/setbit.S
 delete mode 100644 xen/arch/arm/arm32/lib/testchangebit.S
 delete mode 100644 xen/arch/arm/arm32/lib/testclearbit.S
 delete mode 100644 xen/arch/arm/arm32/lib/testsetbit.S

diff --git a/xen/arch/arm/README.LinuxPrimitives b/xen/arch/arm/README.LinuxPrimitives
index 891667a5da..664a9f89ed 100644
--- a/xen/arch/arm/README.LinuxPrimitives
+++ b/xen/arch/arm/README.LinuxPrimitives
@@ -68,19 +68,9 @@ arm32
 
 bitops: last sync @ v3.16-rc6 (last commit: c32ffce0f66e)
 
-linux/arch/arm/lib/bitops.h             xen/arch/arm/arm32/lib/bitops.h
-linux/arch/arm/lib/changebit.S          xen/arch/arm/arm32/lib/changebit.S
-linux/arch/arm/lib/clearbit.S           xen/arch/arm/arm32/lib/clearbit.S
 linux/arch/arm/lib/findbit.S            xen/arch/arm/arm32/lib/findbit.S
-linux/arch/arm/lib/setbit.S             xen/arch/arm/arm32/lib/setbit.S
-linux/arch/arm/lib/testchangebit.S      xen/arch/arm/arm32/lib/testchangebit.S
-linux/arch/arm/lib/testclearbit.S       xen/arch/arm/arm32/lib/testclearbit.S
-linux/arch/arm/lib/testsetbit.S         xen/arch/arm/arm32/lib/testsetbit.S
-
-for i in bitops.h changebit.S clearbit.S findbit.S setbit.S testchangebit.S \
-         testclearbit.S testsetbit.S; do
-    diff -u ../linux/arch/arm/lib/$i xen/arch/arm/arm32/lib/$i;
-done
+
+diff -u ../linux/arch/arm/lib/findbit.S xen/arch/arm/arm32/lib/findbit.S
 
 ---------------------------------------------------------------------
 
diff --git a/xen/arch/arm/arm32/lib/Makefile b/xen/arch/arm/arm32/lib/Makefile
index e9fbc595b9..b1457c89dc 100644
--- a/xen/arch/arm/arm32/lib/Makefile
+++ b/xen/arch/arm/arm32/lib/Makefile
@@ -1,6 +1,5 @@
 obj-y += memcpy.o memmove.o memset.o memchr.o memzero.o
-obj-y += findbit.o setbit.o
-obj-y += setbit.o clearbit.o changebit.o
-obj-y += testsetbit.o testclearbit.o testchangebit.o
+obj-y += findbit.o
+obj-y += bitops.o
 obj-y += strchr.o strrchr.o
 obj-y += lib1funcs.o lshrdi3.o div64.o
diff --git a/xen/arch/arm/arm32/lib/bitops.c b/xen/arch/arm/arm32/lib/bitops.c
new file mode 100644
index 0000000000..c69bb53037
--- /dev/null
+++ b/xen/arch/arm/arm32/lib/bitops.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/bitops.h>
+#include <xen/prefetch.h>
+#include <asm/system.h>
+
+/*
+ * The atomic bit operations pass the number of bit in a signed number
+ * (not sure why). This has the drawback to increase the complexity of
+ * the resulting assembly.
+ *
+ * To generate simpler code, the number of bit (nr) will be cast to
+ * unsigned int.
+ *
+ * XXX: Rework the interface to use unsigned int.
+ */
+
+#define bitop(name, instr)                                                  \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
+    unsigned long res, tmp;                                                 \
+                                                                            \
+    ASSERT(((vaddr_t)p & 0x3) == 0);                                        \
+    prefetchw((const void *)ptr);                                           \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldrex   %2, %1\n"                                               \
+        "   " __stringify(instr) "     %2, %2, %3\n"                        \
+        "   strex   %0, %2, %1\n"                                           \
+        : "=&r" (res), "+Qo" (*ptr), "=&r" (tmp)                            \
+        : "r" (mask));                                                      \
+    } while ( res );                                                        \
+}
+
+#define testop(name, instr)                                                 \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
+    const uint32_t mask = BIT_MASK(bit);                                    \
+    unsigned long res, tmp;                                                 \
+    int oldbit;                                                             \
+                                                                            \
+    ASSERT(((vaddr_t)p & 0x3) == 0);                                        \
+    smp_mb();                                                               \
+                                                                            \
+    prefetchw((const void *)ptr);                                           \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldrex   %3, %2\n"                                               \
+        "   lsr     %1, %3, %5 // Save old value of bit\n"                  \
+        "   " __stringify(instr) "  %3, %3, %4 // Toggle bit\n"             \
+        "   strex  %0, %3, %2\n"                                            \
+        : "=&r" (res), "=&r" (oldbit), "+Qo" (*ptr), "=&r" (tmp)            \
+        : "r" (mask), "r" (bit));                                           \
+    } while ( res );                                                        \
+                                                                            \
+    smp_mb();                                                               \
+                                                                            \
+    return oldbit & 1;                                                      \
+}                                                                           \
+
+bitop(change_bit, eor)
+bitop(clear_bit, bic)
+bitop(set_bit, orr)
+
+testop(test_and_change_bit, eor)
+testop(test_and_clear_bit, bic)
+testop(test_and_set_bit, orr)
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/arm32/lib/bitops.h b/xen/arch/arm/arm32/lib/bitops.h
deleted file mode 100644
index d5e13476f4..0000000000
--- a/xen/arch/arm/arm32/lib/bitops.h
+++ /dev/null
@@ -1,104 +0,0 @@
-
-#if __LINUX_ARM_ARCH__ >= 6
-	.macro	bitop, name, instr
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	mov	r2, #1
-	and	r3, r0, #31		@ Get bit offset
-	mov	r0, r0, lsr #5
-	add	r1, r1, r0, lsl #2	@ Get word offset
-#if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
-	.arch_extension	mp
-	ALT_SMP(W(pldw)	[r1])
-	ALT_UP(W(nop))
-#endif
-	mov	r3, r2, lsl r3
-1:	ldrex	r2, [r1]
-	\instr	r2, r2, r3
-	strex	r0, r2, [r1]
-	cmp	r0, #0
-	bne	1b
-	bx	lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-
-	.macro	testop, name, instr, store
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	mov	r2, #1
-	and	r3, r0, #31		@ Get bit offset
-	mov	r0, r0, lsr #5
-	add	r1, r1, r0, lsl #2	@ Get word offset
-	mov	r3, r2, lsl r3		@ create mask
-	smp_dmb
-#if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
-	.arch_extension	mp
-	ALT_SMP(W(pldw)	[r1])
-	ALT_UP(W(nop))
-#endif
-1:	ldrex	r2, [r1]
-	ands	r0, r2, r3		@ save old value of bit
-	\instr	r2, r2, r3		@ toggle bit
-	strex	ip, r2, [r1]
-	cmp	ip, #0
-	bne	1b
-	smp_dmb
-	cmp	r0, #0
-	movne	r0, #1
-2:	bx	lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-#else
-	.macro	bitop, name, instr
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	and	r2, r0, #31
-	mov	r0, r0, lsr #5
-	mov	r3, #1
-	mov	r3, r3, lsl r2
-	save_and_disable_irqs ip
-	ldr	r2, [r1, r0, lsl #2]
-	\instr	r2, r2, r3
-	str	r2, [r1, r0, lsl #2]
-	restore_irqs ip
-	mov	pc, lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-
-/**
- * testop - implement a test_and_xxx_bit operation.
- * @instr: operational instruction
- * @store: store instruction
- *
- * Note: we can trivially conditionalise the store instruction
- * to avoid dirtying the data cache.
- */
-	.macro	testop, name, instr, store
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	and	r3, r0, #31
-	mov	r0, r0, lsr #5
-	save_and_disable_irqs ip
-	ldr	r2, [r1, r0, lsl #2]!
-	mov	r0, #1
-	tst	r2, r0, lsl r3
-	\instr	r2, r2, r0, lsl r3
-	\store	r2, [r1]
-	moveq	r0, #0
-	restore_irqs ip
-	mov	pc, lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-#endif
diff --git a/xen/arch/arm/arm32/lib/changebit.S b/xen/arch/arm/arm32/lib/changebit.S
deleted file mode 100644
index 6e4ae7594a..0000000000
--- a/xen/arch/arm/arm32/lib/changebit.S
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- *  linux/arch/arm/lib/changebit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-bitop	_change_bit, eor
diff --git a/xen/arch/arm/arm32/lib/clearbit.S b/xen/arch/arm/arm32/lib/clearbit.S
deleted file mode 100644
index fda553f246..0000000000
--- a/xen/arch/arm/arm32/lib/clearbit.S
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- *  linux/arch/arm/lib/clearbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-bitop	_clear_bit, bic
diff --git a/xen/arch/arm/arm32/lib/setbit.S b/xen/arch/arm/arm32/lib/setbit.S
deleted file mode 100644
index d52f0ab65c..0000000000
--- a/xen/arch/arm/arm32/lib/setbit.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- *  linux/arch/arm/lib/setbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "assembler.h"
-#include "bitops.h"
-	.text
-
-bitop	_set_bit, orr
diff --git a/xen/arch/arm/arm32/lib/testchangebit.S b/xen/arch/arm/arm32/lib/testchangebit.S
deleted file mode 100644
index d83b04c057..0000000000
--- a/xen/arch/arm/arm32/lib/testchangebit.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- *  linux/arch/arm/lib/testchangebit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-testop	_test_and_change_bit, eor, str
diff --git a/xen/arch/arm/arm32/lib/testclearbit.S b/xen/arch/arm/arm32/lib/testclearbit.S
deleted file mode 100644
index 6f5b7b92d1..0000000000
--- a/xen/arch/arm/arm32/lib/testclearbit.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- *  linux/arch/arm/lib/testclearbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-testop	_test_and_clear_bit, bicne, strne
diff --git a/xen/arch/arm/arm32/lib/testsetbit.S b/xen/arch/arm/arm32/lib/testsetbit.S
deleted file mode 100644
index 30425a842a..0000000000
--- a/xen/arch/arm/arm32/lib/testsetbit.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- *  linux/arch/arm/lib/testsetbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-testop	_test_and_set_bit, orreq, streq
diff --git a/xen/include/asm-arm/arm32/bitops.h b/xen/include/asm-arm/arm32/bitops.h
index 8be3564540..67c4c3f55c 100644
--- a/xen/include/asm-arm/arm32/bitops.h
+++ b/xen/include/asm-arm/arm32/bitops.h
@@ -1,19 +1,12 @@
 #ifndef _ARM_ARM32_BITOPS_H
 #define _ARM_ARM32_BITOPS_H
 
-extern void _set_bit(int nr, volatile void * p);
-extern void _clear_bit(int nr, volatile void * p);
-extern void _change_bit(int nr, volatile void * p);
-extern int _test_and_set_bit(int nr, volatile void * p);
-extern int _test_and_clear_bit(int nr, volatile void * p);
-extern int _test_and_change_bit(int nr, volatile void * p);
-
-#define set_bit(n,p)              _set_bit(n,p)
-#define clear_bit(n,p)            _clear_bit(n,p)
-#define change_bit(n,p)           _change_bit(n,p)
-#define test_and_set_bit(n,p)     _test_and_set_bit(n,p)
-#define test_and_clear_bit(n,p)   _test_and_clear_bit(n,p)
-#define test_and_change_bit(n,p)  _test_and_change_bit(n,p)
+extern void set_bit(int nr, volatile void * p);
+extern void clear_bit(int nr, volatile void * p);
+extern void change_bit(int nr, volatile void * p);
+extern int test_and_set_bit(int nr, volatile void * p);
+extern int test_and_clear_bit(int nr, volatile void * p);
+extern int test_and_change_bit(int nr, volatile void * p);
 
 #define flsl fls
 
-- 
2.17.1
xsa295/4.12-07.patch (application/octet-stream, 2.7 KB)
From 244df788936cb47ee5479617ebf1d1e8b656266b Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:20 +0100
Subject: [PATCH v2 4.12 07/17] xen/arm: bitops: Consolidate prototypes in one
 place

The prototype are the same between arm32 and arm64. Consolidate them in
asm-arm/bitops.h.

This change will help the introductions of new helpers in a follow-up
patch.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm32/bitops.h |  7 -------
 xen/include/asm-arm/arm64/bitops.h | 10 ----------
 xen/include/asm-arm/bitops.h       |  8 ++++++++
 3 files changed, 8 insertions(+), 17 deletions(-)

diff --git a/xen/include/asm-arm/arm32/bitops.h b/xen/include/asm-arm/arm32/bitops.h
index 67c4c3f55c..57938a5874 100644
--- a/xen/include/asm-arm/arm32/bitops.h
+++ b/xen/include/asm-arm/arm32/bitops.h
@@ -1,13 +1,6 @@
 #ifndef _ARM_ARM32_BITOPS_H
 #define _ARM_ARM32_BITOPS_H
 
-extern void set_bit(int nr, volatile void * p);
-extern void clear_bit(int nr, volatile void * p);
-extern void change_bit(int nr, volatile void * p);
-extern int test_and_set_bit(int nr, volatile void * p);
-extern int test_and_clear_bit(int nr, volatile void * p);
-extern int test_and_change_bit(int nr, volatile void * p);
-
 #define flsl fls
 
 /*
diff --git a/xen/include/asm-arm/arm64/bitops.h b/xen/include/asm-arm/arm64/bitops.h
index 6bf1922680..6cc224ad13 100644
--- a/xen/include/asm-arm/arm64/bitops.h
+++ b/xen/include/asm-arm/arm64/bitops.h
@@ -1,16 +1,6 @@
 #ifndef _ARM_ARM64_BITOPS_H
 #define _ARM_ARM64_BITOPS_H
 
-/*
- * Little endian assembly atomic bitops.
- */
-extern void set_bit(int nr, volatile void *p);
-extern void clear_bit(int nr, volatile void *p);
-extern void change_bit(int nr, volatile void *p);
-extern int test_and_set_bit(int nr, volatile void *p);
-extern int test_and_clear_bit(int nr, volatile void *p);
-extern int test_and_change_bit(int nr, volatile void *p);
-
 /* Based on linux/include/asm-generic/bitops/builtin-__ffs.h */
 /**
  * __ffs - find first bit in word.
diff --git a/xen/include/asm-arm/bitops.h b/xen/include/asm-arm/bitops.h
index 1cbfb9edb2..c69b08adf6 100644
--- a/xen/include/asm-arm/bitops.h
+++ b/xen/include/asm-arm/bitops.h
@@ -38,6 +38,14 @@
 # error "unknown ARM variant"
 #endif
 
+/* Atomics bitops */
+void set_bit(int nr, volatile void *p);
+void clear_bit(int nr, volatile void *p);
+void change_bit(int nr, volatile void *p);
+int test_and_set_bit(int nr, volatile void *p);
+int test_and_clear_bit(int nr, volatile void *p);
+int test_and_change_bit(int nr, volatile void *p);
+
 /**
  * __test_and_set_bit - Set a bit and return its old value
  * @nr: Bit to set
-- 
2.17.1
xsa295/4.12-08.patch (application/octet-stream, 3.7 KB)
From 25f650e4dbf25f1aff1a4c9d509ca7f0ed8da104 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Wed, 22 May 2019 13:37:53 -0700
Subject: [PATCH v2 4.12 08/17] xen/arm64: cmpxchg: Simplify the cmpxchg
 implementation

The only difference between each case of the cmpxchg is the size of
used. Rather than duplicating the code, provide a macro to generate each
cases.

This makes the code easier to read and modify.

This is part of XSA-295.

Signed-off-by; Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm64/cmpxchg.h | 98 +++++++++++------------------
 1 file changed, 36 insertions(+), 62 deletions(-)

diff --git a/xen/include/asm-arm/arm64/cmpxchg.h b/xen/include/asm-arm/arm64/cmpxchg.h
index ae42b2f5ff..393fbca6a5 100644
--- a/xen/include/asm-arm/arm64/cmpxchg.h
+++ b/xen/include/asm-arm/arm64/cmpxchg.h
@@ -61,80 +61,54 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
 	__ret; \
 })
 
-extern void __bad_cmpxchg(volatile void *ptr, int size);
+extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
+
+#define __CMPXCHG_CASE(w, sz, name)					\
+static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
+						  unsigned long old,	\
+						  unsigned long new)	\
+{									\
+	unsigned long res, oldval;					\
+									\
+	do {								\
+		asm volatile("// __cmpxchg_case_" #name "\n"		\
+		"	ldxr" #sz "	%" #w "1, %2\n"			\
+		"	mov	%w0, #0\n"				\
+		"	cmp	%" #w "1, %" #w "3\n"			\
+		"	b.ne	1f\n"					\
+		"	stxr" #sz "	%w0, %" #w "4, %2\n"		\
+		"1:\n"							\
+		: "=&r" (res), "=&r" (oldval),				\
+		  "+Q" (*(unsigned long *)ptr)				\
+		: "Ir" (old), "r" (new)					\
+		: "cc");						\
+	} while (res);							\
+									\
+	return oldval;							\
+}
+
+__CMPXCHG_CASE(w, b, 1)
+__CMPXCHG_CASE(w, h, 2)
+__CMPXCHG_CASE(w,  , 4)
+__CMPXCHG_CASE( ,  , 8)
 
 static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 				      unsigned long new, int size)
 {
-	unsigned long oldval = 0, res;
-
 	switch (size) {
 	case 1:
-		do {
-			asm volatile("// __cmpxchg1\n"
-			"	ldxrb	%w1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%w1, %w3\n"
-			"	b.ne	1f\n"
-			"	stxrb	%w0, %w4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u8 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_1(ptr, old, new);
 	case 2:
-		do {
-			asm volatile("// __cmpxchg2\n"
-			"	ldxrh	%w1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%w1, %w3\n"
-			"	b.ne	1f\n"
-			"	stxrh	%w0, %w4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u16 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_2(ptr, old, new);
 	case 4:
-		do {
-			asm volatile("// __cmpxchg4\n"
-			"	ldxr	%w1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%w1, %w3\n"
-			"	b.ne	1f\n"
-			"	stxr	%w0, %w4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u32 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_4(ptr, old, new);
 	case 8:
-		do {
-			asm volatile("// __cmpxchg8\n"
-			"	ldxr	%1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%1, %3\n"
-			"	b.ne	1f\n"
-			"	stxr	%w0, %4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u64 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_8(ptr, old, new);
 	default:
-		__bad_cmpxchg(ptr, size);
-		oldval = 0;
+		return __bad_cmpxchg(ptr, size);
 	}
 
-	return oldval;
+	ASSERT_UNREACHABLE();
 }
 
 static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
-- 
2.17.1
xsa295/4.12-09.patch (application/octet-stream, 3.6 KB)
From f33610438bb6586eb665922d9f32bb2889220b2b Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:22 +0100
Subject: [PATCH v2 4.12 09/17] xen/arm32: cmpxchg: Simplify the cmpxchg
 implementation

The only difference between each case of the cmpxchg is the size of
used. Rather than duplicating the code, provide a macro to generate each
cases.

This makes the code easier to read and modify.

While doing the rework, the case for 64-bit cmpxchg is removed. This is
unused today (already commented) and it would not be possible to use
it directly.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm32/cmpxchg.h | 84 +++++++++++------------------
 1 file changed, 31 insertions(+), 53 deletions(-)

diff --git a/xen/include/asm-arm/arm32/cmpxchg.h b/xen/include/asm-arm/arm32/cmpxchg.h
index 03e0bed3a6..471a9e3a3f 100644
--- a/xen/include/asm-arm/arm32/cmpxchg.h
+++ b/xen/include/asm-arm/arm32/cmpxchg.h
@@ -52,72 +52,50 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
  * indicated by comparing RETURN with OLD.
  */
 
-extern void __bad_cmpxchg(volatile void *ptr, int size);
+extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
+
+#define __CMPXCHG_CASE(sz, name)					\
+static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
+						  unsigned long old,	\
+						  unsigned long new)	\
+{									\
+	unsigned long oldval, res;					\
+									\
+	do {								\
+		asm volatile("@ __cmpxchg_case_" #name "\n"		\
+		"	ldrex" #sz "	%1, [%2]\n"			\
+		"	mov	%0, #0\n"				\
+		"	teq	%1, %3\n"				\
+		"	strex" #sz "eq %0, %4, [%2]\n"			\
+		: "=&r" (res), "=&r" (oldval)				\
+		: "r" (ptr), "Ir" (old), "r" (new)			\
+		: "memory", "cc");					\
+	} while (res);							\
+									\
+	return oldval;							\
+}
+
+__CMPXCHG_CASE(b, 1)
+__CMPXCHG_CASE(h, 2)
+__CMPXCHG_CASE( , 4)
 
 static always_inline unsigned long __cmpxchg(
     volatile void *ptr, unsigned long old, unsigned long new, int size)
 {
-	unsigned long oldval, res;
-
 	prefetchw((const void *)ptr);
 
 	switch (size) {
 	case 1:
-		do {
-			asm volatile("@ __cmpxchg1\n"
-			"	ldrexb	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexbeq %0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-		} while (res);
-		break;
+		return __cmpxchg_case_1(ptr, old, new);
 	case 2:
-		do {
-			asm volatile("@ __cmpxchg2\n"
-			"	ldrexh	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexheq %0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-		} while (res);
-		break;
+		return __cmpxchg_case_2(ptr, old, new);
 	case 4:
-		do {
-			asm volatile("@ __cmpxchg4\n"
-			"	ldrex	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexeq	%0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-	    } while (res);
-	    break;
-#if 0
-	case 8:
-		do {
-			asm volatile("@ __cmpxchg8\n"
-			"	ldrexd	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexdeq %0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-		} while (res);
-		break;
-#endif
+		return __cmpxchg_case_4(ptr, old, new);
 	default:
-		__bad_cmpxchg(ptr, size);
-		oldval = 0;
+		return __bad_cmpxchg(ptr, size);
 	}
 
-	return oldval;
+	ASSERT_UNREACHABLE();
 }
 
 static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
-- 
2.17.1
xsa295/4.12-10.patch (application/octet-stream, 15.3 KB)
From 7cd0aeaa3ef96180ed251d66a4aff8ffad8c3dfe Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:23 +0100
Subject: [PATCH v2 4.12 10/17] xen/arm: bitops: Implement a new set of helpers
 that can timeout

Exclusive load-store atomics should only be used between trusted
threads. As not all the guests are trusted, it may be possible to DoS
Xen when updating shared memory with guest atomically.

To prevent the infinite loop, we introduce a new set of helpers that can
timeout. The timeout is based on the maximum number of iterations.

They will be used in follow-up patch to make atomic operations
on shared memory safe.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/arm32/lib/bitops.c | 52 ++++++++++++++++++++++++++++-----
 xen/arch/arm/arm64/lib/bitops.c | 52 ++++++++++++++++++++++++++++-----
 xen/include/asm-arm/bitops.h    | 28 +++++++++++++++++-
 3 files changed, 117 insertions(+), 15 deletions(-)

diff --git a/xen/arch/arm/arm32/lib/bitops.c b/xen/arch/arm/arm32/lib/bitops.c
index c69bb53037..08750314fc 100644
--- a/xen/arch/arm/arm32/lib/bitops.c
+++ b/xen/arch/arm/arm32/lib/bitops.c
@@ -30,7 +30,8 @@
  */
 
 #define bitop(name, instr)                                                  \
-void name(int nr, volatile void *p)                                         \
+static always_inline bool int_##name(int nr, volatile void *p, bool timeout,\
+                                     unsigned int max_try)                  \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
@@ -47,17 +48,33 @@ void name(int nr, volatile void *p)                                         \
         "   strex   %0, %2, %1\n"                                           \
         : "=&r" (res), "+Qo" (*ptr), "=&r" (tmp)                            \
         : "r" (mask));                                                      \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
+                                                                            \
+    return !res;                                                            \
+}                                                                           \
+                                                                            \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    if ( !int_##name(nr, p, false, 0) )                                     \
+        ASSERT_UNREACHABLE();                                               \
+}                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p, unsigned int max_try)         \
+{                                                                           \
+    return int_##name(nr, p, true, max_try);                                \
 }
 
 #define testop(name, instr)                                                 \
-int name(int nr, volatile void *p)                                          \
+static always_inline bool int_##name(int nr, volatile void *p, int *oldbit, \
+                                     bool timeout, unsigned int max_try)    \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
     const uint32_t mask = BIT_MASK(bit);                                    \
     unsigned long res, tmp;                                                 \
-    int oldbit;                                                             \
                                                                             \
     ASSERT(((vaddr_t)p & 0x3) == 0);                                        \
     smp_mb();                                                               \
@@ -71,14 +88,35 @@ int name(int nr, volatile void *p)                                          \
         "   lsr     %1, %3, %5 // Save old value of bit\n"                  \
         "   " __stringify(instr) "  %3, %3, %4 // Toggle bit\n"             \
         "   strex  %0, %3, %2\n"                                            \
-        : "=&r" (res), "=&r" (oldbit), "+Qo" (*ptr), "=&r" (tmp)            \
+        : "=&r" (res), "=&r" (*oldbit), "+Qo" (*ptr), "=&r" (tmp)           \
         : "r" (mask), "r" (bit));                                           \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
                                                                             \
     smp_mb();                                                               \
                                                                             \
-    return oldbit & 1;                                                      \
+    *oldbit &= 1;                                                           \
+                                                                            \
+    return !res;                                                            \
+}                                                                           \
+                                                                            \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    int oldbit;                                                             \
+                                                                            \
+    if ( !int_##name(nr, p, &oldbit, false, 0) )                            \
+        ASSERT_UNREACHABLE();                                               \
+                                                                            \
+    return oldbit;                                                          \
 }                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p,                               \
+                    int *oldbit, unsigned int max_try)                      \
+{                                                                           \
+    return int_##name(nr, p, oldbit, true, max_try);                        \
+}
 
 bitop(change_bit, eor)
 bitop(clear_bit, bic)
diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
index b1c681c642..78bf4ed8c5 100644
--- a/xen/arch/arm/arm64/lib/bitops.c
+++ b/xen/arch/arm/arm64/lib/bitops.c
@@ -29,7 +29,8 @@
  */
 
 #define bitop(name, instr)                                                  \
-void name(int nr, volatile void *p)                                         \
+static always_inline bool int_##name(int nr, volatile void *p, bool timeout,\
+                                     unsigned int max_try)                  \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
@@ -43,17 +44,33 @@ void name(int nr, volatile void *p)                                         \
         "   stxr    %w0, %w2, %1\n"                                         \
         : "=&r" (res), "+Q" (*ptr), "=&r" (tmp)                             \
         : "r" (mask));                                                      \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
+                                                                            \
+    return !res;                                                            \
 }                                                                           \
+                                                                            \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    if ( !int_##name(nr, p, false, 0) )                                     \
+        ASSERT_UNREACHABLE();                                               \
+}                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p, unsigned int max_try)         \
+{                                                                           \
+    return int_##name(nr, p, true, max_try);                                \
+}
 
 #define testop(name, instr)                                                 \
-int name(int nr, volatile void *p)                                          \
+static always_inline bool int_##name(int nr, volatile void *p, int *oldbit, \
+                                     bool timeout, unsigned int max_try)    \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
     const uint32_t mask = BIT_MASK(bit);                                    \
     unsigned long res, tmp;                                                 \
-    unsigned long oldbit;                                                   \
                                                                             \
     do                                                                      \
     {                                                                       \
@@ -62,14 +79,35 @@ int name(int nr, volatile void *p)                                          \
         "   lsr     %w1, %w3, %w5 // Save old value of bit\n"               \
         "   " __stringify(instr) "  %w3, %w3, %w4 // Toggle bit\n"          \
         "   stlxr   %w0, %w3, %2\n"                                         \
-        : "=&r" (res), "=&r" (oldbit), "+Q" (*ptr), "=&r" (tmp)             \
+        : "=&r" (res), "=&r" (*oldbit), "+Q" (*ptr), "=&r" (tmp)            \
         : "r" (mask), "r" (bit)                                             \
         : "memory");                                                        \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
                                                                             \
     dmb(ish);                                                               \
                                                                             \
-    return oldbit & 1;                                                      \
+    *oldbit &= 1;                                                           \
+                                                                            \
+    return !res;                                                            \
+}                                                                           \
+                                                                            \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    int oldbit;                                                             \
+                                                                            \
+    if ( !int_##name(nr, p, &oldbit, false, 0) )                            \
+        ASSERT_UNREACHABLE();                                               \
+                                                                            \
+    return oldbit;                                                          \
+}                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p,                               \
+                    int *oldbit, unsigned int max_try)                      \
+{                                                                           \
+    return int_##name(nr, p, oldbit, true, max_try);                        \
 }
 
 bitop(change_bit, eor)
diff --git a/xen/include/asm-arm/bitops.h b/xen/include/asm-arm/bitops.h
index c69b08adf6..f6782b33be 100644
--- a/xen/include/asm-arm/bitops.h
+++ b/xen/include/asm-arm/bitops.h
@@ -38,7 +38,14 @@
 # error "unknown ARM variant"
 #endif
 
-/* Atomics bitops */
+/*
+ * Atomic bitops
+ *
+ * The helpers below *should* only be used on memory shared between
+ * trusted threads or we know the memory cannot be accessed by another
+ * thread.
+ */
+
 void set_bit(int nr, volatile void *p);
 void clear_bit(int nr, volatile void *p);
 void change_bit(int nr, volatile void *p);
@@ -46,6 +53,25 @@ int test_and_set_bit(int nr, volatile void *p);
 int test_and_clear_bit(int nr, volatile void *p);
 int test_and_change_bit(int nr, volatile void *p);
 
+/*
+ * The helpers below may fail to update the memory if the action takes
+ * too long.
+ *
+ * @max_try: Maximum number of iterations
+ *
+ * The helpers will return true when the update has succeeded (i.e no
+ * timeout) and false if the update has failed.
+ */
+bool set_bit_timeout(int nr, volatile void *p, unsigned int max_try);
+bool clear_bit_timeout(int nr, volatile void *p, unsigned int max_try);
+bool change_bit_timeout(int nr, volatile void *p, unsigned int max_try);
+bool test_and_set_bit_timeout(int nr, volatile void *p,
+                              int *oldbit, unsigned int max_try);
+bool test_and_clear_bit_timeout(int nr, volatile void *p,
+                                int *oldbit, unsigned int max_try);
+bool test_and_change_bit_timeout(int nr, volatile void *p,
+                                 int *oldbit, unsigned int max_try);
+
 /**
  * __test_and_set_bit - Set a bit and return its old value
  * @nr: Bit to set
-- 
2.17.1
xsa295/4.12-11.patch (application/octet-stream, 8.3 KB)
From 9a6ac9945d1d742185189a7d751d3ad10c8bed3f Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Wed, 22 May 2019 13:39:17 -0700
Subject: [PATCH v2 4.12 11/17] xen/arm: cmpxchg: Provide a new helper that can
 timeout

Exclusive load-store atomics should only be used between trusted
threads. As not all the guests are trusted, it may be possible to DoS
Xen when updating shared memory with guest atomically.

To prevent the infinite loop, we introduce a new helper that can timeout.
The timeout is based on the maximum number of iterations.

It will be used in follow-up patch to make atomic operations on shared
memory safe.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm32/cmpxchg.h | 63 +++++++++++++++++++++-----
 xen/include/asm-arm/arm64/cmpxchg.h | 70 ++++++++++++++++++++++-------
 2 files changed, 106 insertions(+), 27 deletions(-)

diff --git a/xen/include/asm-arm/arm32/cmpxchg.h b/xen/include/asm-arm/arm32/cmpxchg.h
index 471a9e3a3f..49ca2a0d7a 100644
--- a/xen/include/asm-arm/arm32/cmpxchg.h
+++ b/xen/include/asm-arm/arm32/cmpxchg.h
@@ -55,11 +55,14 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
 extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
 
 #define __CMPXCHG_CASE(sz, name)					\
-static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
-						  unsigned long old,	\
-						  unsigned long new)	\
+static inline bool __cmpxchg_case_##name(volatile void *ptr,		\
+					 unsigned long *old,		\
+					 unsigned long new,		\
+					 bool timeout,			\
+					 unsigned int max_try)		\
 {									\
-	unsigned long oldval, res;					\
+	unsigned long oldval;						\
+	unsigned long res;						\
 									\
 	do {								\
 		asm volatile("@ __cmpxchg_case_" #name "\n"		\
@@ -68,29 +71,35 @@ static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
 		"	teq	%1, %3\n"				\
 		"	strex" #sz "eq %0, %4, [%2]\n"			\
 		: "=&r" (res), "=&r" (oldval)				\
-		: "r" (ptr), "Ir" (old), "r" (new)			\
+		: "r" (ptr), "Ir" (*old), "r" (new)			\
 		: "memory", "cc");					\
-	} while (res);							\
 									\
-	return oldval;							\
+		if (!res)						\
+			break;						\
+	} while (!timeout || ((--max_try) > 0));			\
+									\
+	*old = oldval;							\
+									\
+	return !res;							\
 }
 
 __CMPXCHG_CASE(b, 1)
 __CMPXCHG_CASE(h, 2)
 __CMPXCHG_CASE( , 4)
 
-static always_inline unsigned long __cmpxchg(
-    volatile void *ptr, unsigned long old, unsigned long new, int size)
+static always_inline bool __int_cmpxchg(volatile void *ptr, unsigned long *old,
+					unsigned long new, int size,
+					bool timeout, unsigned int max_try)
 {
 	prefetchw((const void *)ptr);
 
 	switch (size) {
 	case 1:
-		return __cmpxchg_case_1(ptr, old, new);
+		return __cmpxchg_case_1(ptr, old, new, timeout, max_try);
 	case 2:
-		return __cmpxchg_case_2(ptr, old, new);
+		return __cmpxchg_case_2(ptr, old, new, timeout, max_try);
 	case 4:
-		return __cmpxchg_case_4(ptr, old, new);
+		return __cmpxchg_case_4(ptr, old, new, timeout, max_try);
 	default:
 		return __bad_cmpxchg(ptr, size);
 	}
@@ -98,6 +107,17 @@ static always_inline unsigned long __cmpxchg(
 	ASSERT_UNREACHABLE();
 }
 
+static always_inline unsigned long __cmpxchg(volatile void *ptr,
+					     unsigned long old,
+					     unsigned long new,
+					     int size)
+{
+	if (!__int_cmpxchg(ptr, &old, new, size, false, 0))
+		ASSERT_UNREACHABLE();
+
+	return old;
+}
+
 static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
                                                 unsigned long old,
                                                 unsigned long new, int size)
@@ -111,6 +131,25 @@ static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
 	return ret;
 }
 
+/*
+ * The helper may fail to update the memory if the action takes too long.
+ *
+ * @old: On call the value pointed contains the expected old value. It will be
+ * updated to the actual old value.
+ * @max_try: Maximum number of iterations
+ *
+ * The helper will return true when the update has succeeded (i.e no
+ * timeout) and false if the update has failed.
+ */
+static always_inline bool __cmpxchg_mb_timeout(volatile void *ptr,
+					       unsigned long *old,
+					       unsigned long new,
+					       int size,
+					       unsigned int max_try)
+{
+	return __int_cmpxchg(ptr, old, new, size, true, max_try);
+}
+
 #define cmpxchg(ptr,o,n)						\
 	((__typeof__(*(ptr)))__cmpxchg_mb((ptr),			\
 					  (unsigned long)(o),		\
diff --git a/xen/include/asm-arm/arm64/cmpxchg.h b/xen/include/asm-arm/arm64/cmpxchg.h
index 393fbca6a5..5bc2e1f786 100644
--- a/xen/include/asm-arm/arm64/cmpxchg.h
+++ b/xen/include/asm-arm/arm64/cmpxchg.h
@@ -64,11 +64,14 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
 extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
 
 #define __CMPXCHG_CASE(w, sz, name)					\
-static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
-						  unsigned long old,	\
-						  unsigned long new)	\
+static inline bool __cmpxchg_case_##name(volatile void *ptr,		\
+					 unsigned long *old,		\
+					 unsigned long new,		\
+					 bool timeout,			\
+					 unsigned int max_try)		\
 {									\
-	unsigned long res, oldval;					\
+	unsigned long oldval;						\
+	unsigned long res;						\
 									\
 	do {								\
 		asm volatile("// __cmpxchg_case_" #name "\n"		\
@@ -80,11 +83,16 @@ static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
 		"1:\n"							\
 		: "=&r" (res), "=&r" (oldval),				\
 		  "+Q" (*(unsigned long *)ptr)				\
-		: "Ir" (old), "r" (new)					\
+		: "Ir" (*old), "r" (new)				\
 		: "cc");						\
-	} while (res);							\
 									\
-	return oldval;							\
+		if (!res)						\
+			break;						\
+	} while (!timeout || ((--max_try) > 0));			\
+									\
+	*old = oldval;							\
+									\
+	return !res;							\
 }
 
 __CMPXCHG_CASE(w, b, 1)
@@ -92,18 +100,19 @@ __CMPXCHG_CASE(w, h, 2)
 __CMPXCHG_CASE(w,  , 4)
 __CMPXCHG_CASE( ,  , 8)
 
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
-				      unsigned long new, int size)
+static always_inline bool __int_cmpxchg(volatile void *ptr, unsigned long *old,
+					unsigned long new, int size,
+					bool timeout, unsigned int max_try)
 {
 	switch (size) {
 	case 1:
-		return __cmpxchg_case_1(ptr, old, new);
+		return __cmpxchg_case_1(ptr, old, new, timeout, max_try);
 	case 2:
-		return __cmpxchg_case_2(ptr, old, new);
+		return __cmpxchg_case_2(ptr, old, new, timeout, max_try);
 	case 4:
-		return __cmpxchg_case_4(ptr, old, new);
+		return __cmpxchg_case_4(ptr, old, new, timeout, max_try);
 	case 8:
-		return __cmpxchg_case_8(ptr, old, new);
+		return __cmpxchg_case_8(ptr, old, new, timeout, max_try);
 	default:
 		return __bad_cmpxchg(ptr, size);
 	}
@@ -111,8 +120,20 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 	ASSERT_UNREACHABLE();
 }
 
-static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
-					 unsigned long new, int size)
+static always_inline unsigned long __cmpxchg(volatile void *ptr,
+					     unsigned long old,
+					     unsigned long new,
+					     int size)
+{
+	if (!__int_cmpxchg(ptr, &old, new, size, false, 0))
+		ASSERT_UNREACHABLE();
+
+	return old;
+}
+
+static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
+						unsigned long old,
+						unsigned long new, int size)
 {
 	unsigned long ret;
 
@@ -123,6 +144,25 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
 	return ret;
 }
 
+/*
+ * The helper may fail to update the memory if the action takes too long.
+ *
+ * @old: On call the value pointed contains the expected old value. It will be
+ * updated to the actual old value.
+ * @max_try: Maximum number of iterations
+ *
+ * The helper will return true when the update has succeeded (i.e no
+ * timeout) and false if the update has failed.
+ */
+static always_inline bool __cmpxchg_mb_timeout(volatile void *ptr,
+					       unsigned long *old,
+					       unsigned long new,
+					       int size,
+					       unsigned int max_try)
+{
+	return __int_cmpxchg(ptr, old, new, size, true, max_try);
+}
+
 #define cmpxchg(ptr, o, n) \
 ({ \
 	__typeof__(*(ptr)) __ret; \
-- 
2.17.1
xsa295/4.12-12.patch (application/octet-stream, 3.5 KB)
From 07c47ec0a6aa0c76e6822127ea5ec5122c9282a0 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:25 +0100
Subject: [PATCH v2 4.12 12/17] xen/arm: Turn on SILO mode by default on Arm

On Arm, exclusive load-store atomics should only be used between trusted
thread. As not all the guests are trusted, it may be possible to DoS Xen
when updating shared memory with guest atomically.

Recent patches introduced new helpers to update shared memory with guest
atomically. Those helpers relies on a memory region to be be shared with
Xen and a single guest.

At the moment, nothing prevent a guest sharing a page with Xen and as
well with another guest (e.g via grant table).

For the scope of the XSA, the quickest way is to deny communications
between unprivileged guest. So this patch is enabling and using SILO
mode by default on Arm.

Users wanted finer graine policy could wrote their own Flask policy.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Acked-by: Jan Beulich <[email protected]>
---
 xen/arch/arm/setup.c  | 8 ++++++--
 xen/common/Kconfig    | 3 ++-
 xen/include/xsm/xsm.h | 5 +++++
 xen/xsm/xsm_core.c    | 2 +-
 4 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index 444857a967..a2aedc43e2 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -39,6 +39,7 @@
 #include <xen/trace.h>
 #include <xen/libfdt/libfdt.h>
 #include <xen/acpi.h>
+#include <xen/warning.h>
 #include <asm/alternative.h>
 #include <asm/page.h>
 #include <asm/current.h>
@@ -834,8 +835,11 @@ void __init start_xen(unsigned long boot_phys_offset,
 
     tasklet_subsys_init();
 
-
-    xsm_dt_init();
+    if ( xsm_dt_init() != 1 )
+        warning_add("WARNING: SILO mode is not enabled.\n"
+                    "It has implications on the security of the system,\n"
+                    "unless the communications have been forbidden between\n"
+                    "untrusted domains.\n");
 
     init_maintenance_interrupt();
     init_timer_interrupt();
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index 04384628bb..e9b1006852 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -106,7 +106,7 @@ config XENOPROF
 
 config XSM
 	bool "Xen Security Modules support"
-	default n
+	default ARM
 	---help---
 	  Enables the security framework known as Xen Security Modules which
 	  allows administrators fine-grained control over a Xen domain and
@@ -171,6 +171,7 @@ config XSM_SILO
 choice
 	prompt "Default XSM implementation"
 	depends on XSM
+	default XSM_SILO_DEFAULT if XSM_SILO && ARM
 	default XSM_FLASK_DEFAULT if XSM_FLASK
 	default XSM_SILO_DEFAULT if XSM_SILO
 	default XSM_DUMMY_DEFAULT
diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h
index 8a78d8abd3..fc9d6b5bf0 100644
--- a/xen/include/xsm/xsm.h
+++ b/xen/include/xsm/xsm.h
@@ -741,6 +741,11 @@ extern int xsm_multiboot_policy_init(unsigned long *module_map,
 #endif
 
 #ifdef CONFIG_HAS_DEVICE_TREE
+/*
+ * Initialize XSM
+ *
+ * On success, return 1 if using SILO mode else 0.
+ */
 extern int xsm_dt_init(void);
 extern int xsm_dt_policy_init(void **policy_buffer, size_t *policy_size);
 extern bool has_xsm_magic(paddr_t);
diff --git a/xen/xsm/xsm_core.c b/xen/xsm/xsm_core.c
index 201c354390..a319df253d 100644
--- a/xen/xsm/xsm_core.c
+++ b/xen/xsm/xsm_core.c
@@ -167,7 +167,7 @@ int __init xsm_dt_init(void)
 
     xfree(policy_buffer);
 
-    return ret;
+    return ret ?: (xsm_bootparam == XSM_BOOTPARAM_SILO);
 }
 
 /**
-- 
2.17.1
xsa295/4.12-13.patch (application/octet-stream, 9.6 KB)
From 0566038dc84d91b962e5338a9c12e29c2d7d2e9b Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:26 +0100
Subject: [PATCH v2 4.12 13/17] xen/bitops: Provide helpers to safely modify
 guest memory atomically

On Arm, exclusive load-store atomics should only be used between trusted
thread. As not all the guests are trusted, it may be possible to DoS Xen
when updating shared memory with guest atomically.

This patch adds a new set of helper that will update the guest memory
safely. For x86, it is already possible to use the current helpers
safely. So just wrap them.

For Arm, we will first attempt to update the guest memory with the loop
bounded by a maximum number of iterations. If it fails, we will pause the
domain and try again.

Note that this heuristics assumes that a page can only be shared between
Xen and one domain. Not Xen and multiple domain.

The maximum number of iterations is based on how many times a simple
load-store atomic operation can be executed in 1uS. The maximum value is
per-CPU to cater big.LITTLE and calculated when the CPU is booting. The
heuristic was randomly chosen and can be modified if impact too much
good-behaving guest.

Note, while test_bit does not requires to use atomic operation, a
wrapper for test_bit was added for completeness. In this case, the
domain stays constified to avoid major rework in the caller for the
time-being.

This is part of XSA-295.

Signed-of-by: Julien Grall <[email protected]>
Acked-by: Jan Beulich <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/Makefile               |  1 +
 xen/arch/arm/guest_atomics.c        | 91 +++++++++++++++++++++++++++++
 xen/include/asm-arm/guest_atomics.h | 76 ++++++++++++++++++++++++
 xen/include/asm-x86/guest_atomics.h | 30 ++++++++++
 4 files changed, 198 insertions(+)
 create mode 100644 xen/arch/arm/guest_atomics.c
 create mode 100644 xen/include/asm-arm/guest_atomics.h
 create mode 100644 xen/include/asm-x86/guest_atomics.h

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index cb902cb6fe..872a155b60 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_GICV3) += gic-v3.o
 obj-$(CONFIG_HAS_ITS) += gic-v3-its.o
 obj-$(CONFIG_HAS_ITS) += gic-v3-lpi.o
 obj-y += guestcopy.o
+obj-y += guest_atomics.o
 obj-y += guest_walk.o
 obj-y += hvm.o
 obj-y += io.o
diff --git a/xen/arch/arm/guest_atomics.c b/xen/arch/arm/guest_atomics.c
new file mode 100644
index 0000000000..1b78a062f0
--- /dev/null
+++ b/xen/arch/arm/guest_atomics.c
@@ -0,0 +1,91 @@
+/*
+ * arch/arm/guest_atomics.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <xen/cpu.h>
+
+#include <asm/guest_atomics.h>
+
+DEFINE_PER_CPU_READ_MOSTLY(unsigned int, guest_safe_atomic_max);
+
+/*
+ * Heuristic to find a safe upper-limit for load-store exclusive
+ * operations on memory shared with guest.
+ *
+ * At the moment, we calculate the number of iterations of a simple
+ * load-store atomic loop in 1uS.
+ */
+static void calibrate_safe_atomic(void)
+{
+    s_time_t deadline = NOW() + MICROSECS(1);
+    unsigned int counter = 0;
+    unsigned long mem = 0;
+
+    do
+    {
+        unsigned long res, tmp;
+
+#ifdef CONFIG_ARM_32
+        asm volatile (" ldrex   %2, %1\n"
+                      " add     %2, %2, #1\n"
+                      " strex   %0, %2, %1\n"
+                      : "=&r" (res), "+Q" (mem), "=&r" (tmp));
+#else
+        asm volatile (" ldxr    %w2, %1\n"
+                      " add     %w2, %w2, #1\n"
+                      " stxr    %w0, %w2, %1\n"
+                      : "=&r" (res), "+Q" (mem), "=&r" (tmp));
+#endif
+        counter++;
+    } while (NOW() < deadline);
+
+    this_cpu(guest_safe_atomic_max) = counter;
+
+    printk(XENLOG_DEBUG
+           "CPU%u: Guest atomics will try %u times before pausing the domain\n",
+           smp_processor_id(), counter);
+}
+
+static int cpu_guest_safe_atomic_callback(struct notifier_block *nfb,
+                                          unsigned long action,
+                                          void *hcpu)
+{
+    if ( action == CPU_STARTING )
+        calibrate_safe_atomic();
+
+    return NOTIFY_DONE;
+}
+
+static struct notifier_block cpu_guest_safe_atomic_nfb = {
+    .notifier_call = cpu_guest_safe_atomic_callback,
+};
+
+static int __init guest_safe_atomic_init(void)
+{
+    register_cpu_notifier(&cpu_guest_safe_atomic_nfb);
+
+    calibrate_safe_atomic();
+
+    return 0;
+}
+presmp_initcall(guest_safe_atomic_init);
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-arm/guest_atomics.h b/xen/include/asm-arm/guest_atomics.h
new file mode 100644
index 0000000000..4f127fda41
--- /dev/null
+++ b/xen/include/asm-arm/guest_atomics.h
@@ -0,0 +1,76 @@
+#ifndef _ARM_GUEST_ATOMICS_H
+#define _ARM_GUEST_ATOMICS_H
+
+#include <xen/bitops.h>
+#include <xen/sched.h>
+
+/*
+ * The guest atomics helpers shares the same logic. We first try to use
+ * the *_timeout version of the operation. If it didn't timeout, then we
+ * successfully updated the memory. Nothing else to do.
+ *
+ * If it did timeout, then it means we didn't manage to update the
+ * memory. This is possibly because the guest is misbehaving (i.e tight
+ * store loop) but can also happen for other reasons (i.e nested Xen).
+ * In that case pause the domain and retry the operation, this time
+ * without a timeout.
+ *
+ * Note, those helpers rely on other part of the code to prevent sharing
+ * a page between Xen and multiple domain.
+ */
+
+DECLARE_PER_CPU(unsigned int, guest_safe_atomic_max);
+
+#define guest_bitop(name)                                                   \
+static inline void guest_##name(struct domain *d, int nr, volatile void *p) \
+{                                                                           \
+    if ( name##_timeout(nr, p, this_cpu(guest_safe_atomic_max)) )           \
+        return;                                                             \
+                                                                            \
+    domain_pause_nosync(d);                                                 \
+    name(nr, p);                                                            \
+    domain_unpause(d);                                                      \
+}
+
+#define guest_testop(name)                                                  \
+static inline int guest_##name(struct domain *d, int nr, volatile void *p)  \
+{                                                                           \
+    bool succeed;                                                           \
+    int oldbit;                                                             \
+                                                                            \
+    succeed = name##_timeout(nr, p, &oldbit,                                \
+                             this_cpu(guest_safe_atomic_max));              \
+    if ( succeed )                                                          \
+        return oldbit;                                                      \
+                                                                            \
+    domain_pause_nosync(d);                                                 \
+    oldbit = name(nr, p);                                                   \
+    domain_unpause(d);                                                      \
+                                                                            \
+    return oldbit;                                                          \
+}
+
+guest_bitop(set_bit)
+guest_bitop(clear_bit)
+guest_bitop(change_bit)
+
+#undef guest_bitop
+
+/* test_bit does not use load-store atomic operations */
+#define guest_test_bit(d, nr, p) ((void)(d), test_bit(nr, p))
+
+guest_testop(test_and_set_bit)
+guest_testop(test_and_clear_bit)
+guest_testop(test_and_change_bit)
+
+#undef guest_testop
+
+#endif /* _ARM_GUEST_ATOMICS_H */
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-x86/guest_atomics.h b/xen/include/asm-x86/guest_atomics.h
new file mode 100644
index 0000000000..0c71d2d278
--- /dev/null
+++ b/xen/include/asm-x86/guest_atomics.h
@@ -0,0 +1,30 @@
+#ifndef _X86_GUEST_ATOMICS_H
+#define _X86_GUEST_ATOMICS_H
+
+#include <xen/bitops.h>
+
+/*
+ * It is safe to use the atomics helpers on x86 on memory shared with
+ * the guests.
+ */
+#define guest_set_bit(d, nr, p)     ((void)(d), set_bit(nr, p))
+#define guest_clear_bit(d, nr, p)   ((void)(d), clear_bit(nr, p))
+#define guest_change_bit(d, nr, p)  ((void)(d), change_bit(nr, p))
+#define guest_test_bit(d, nr, p)    ((void)(d), test_bit(nr, p))
+
+#define guest_test_and_set_bit(d, nr, p)    \
+    ((void)(d), test_and_set_bit(nr, p))
+#define guest_test_and_clear_bit(d, nr, p)  \
+    ((void)(d), test_and_clear_bit(nr, p))
+#define guest_test_and_change_bit(d, nr, p) \
+    ((void)(d), test_and_change_bit(nr, p))
+
+#endif /* _X86_GUEST_ATOMICS_H */
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.17.1
xsa295/4.12-14.patch (application/octet-stream, 3.4 KB)
From fefcb78a412f99ea2781595448d60abb690e3246 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:27 +0100
Subject: [PATCH v2 4.12 14/17] xen/cmpxchg: Provide helper to safely modify
 guest memory atomically

On Arm, exclusive load-store atomics should only be used between trusted
thread. As not all the guests are trusted, it may be possible to DoS Xen
when updating shared memory with guest atomically.

This patch adds a new helper that will update the guest memory safely.
For x86, it is already possible to use the current helper safely. So
just wrap it.

For Arm, we will first attempt to update the guest memory with the
loop bounded by a maximum number of iterations. If it fails, we will
pause the domain and try again.

Note that this heuristics assumes that a page can only
be shared between Xen and one domain. Not Xen and multiple domain.

The maximum number of iterations is based on how many times atomic_inc()
can be executed in 1uS. The maximum value is per-CPU to cater big.LITTLE
and calculated when the CPU is booting.

The maximum number of iterations is based on how many times a simple
load-store atomic operation can be executed in 1uS. The maximum
value is per-CPU to cater big.LITTLE and calculated when the CPU is
booting. The heuristic was randomly chosen and can be modified if
impact too much good-behaving guest.

This is part of XSA-295.

Signed-of-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Acked-by: Jan Beulich <[email protected]>
---
 xen/include/asm-arm/guest_atomics.h | 25 +++++++++++++++++++++++++
 xen/include/asm-x86/guest_atomics.h |  2 ++
 2 files changed, 27 insertions(+)

diff --git a/xen/include/asm-arm/guest_atomics.h b/xen/include/asm-arm/guest_atomics.h
index 4f127fda41..61925d313d 100644
--- a/xen/include/asm-arm/guest_atomics.h
+++ b/xen/include/asm-arm/guest_atomics.h
@@ -65,6 +65,31 @@ guest_testop(test_and_change_bit)
 
 #undef guest_testop
 
+static inline unsigned long __guest_cmpxchg(struct domain *d,
+                                            volatile void *ptr,
+                                            unsigned long old,
+                                            unsigned long new,
+                                            unsigned int size)
+{
+    unsigned long oldval = old;
+
+    if ( __cmpxchg_mb_timeout(ptr, &oldval, new, size,
+                              this_cpu(guest_safe_atomic_max)) )
+        return oldval;
+
+    domain_pause_nosync(d);
+    oldval = __cmpxchg_mb(ptr, old, new, size);
+    domain_unpause(d);
+
+    return oldval;
+}
+
+#define guest_cmpxchg(d, ptr, o, n)                         \
+    ((__typeof__(*(ptr)))__guest_cmpxchg(d, ptr,            \
+                                         (unsigned long)(o),\
+                                         (unsigned long)(n),\
+                                         sizeof (*(ptr))))
+
 #endif /* _ARM_GUEST_ATOMICS_H */
 /*
  * Local variables:
diff --git a/xen/include/asm-x86/guest_atomics.h b/xen/include/asm-x86/guest_atomics.h
index 0c71d2d278..029417c8ff 100644
--- a/xen/include/asm-x86/guest_atomics.h
+++ b/xen/include/asm-x86/guest_atomics.h
@@ -19,6 +19,8 @@
 #define guest_test_and_change_bit(d, nr, p) \
     ((void)(d), test_and_change_bit(nr, p))
 
+#define guest_cmpxchg(d, ptr, o, n) ((void)(d), cmpxchg(ptr, o, n))
+
 #endif /* _X86_GUEST_ATOMICS_H */
 /*
  * Local variables:
-- 
2.17.1
xsa295/4.12-15.patch (application/octet-stream, 22.4 KB)
From d7bf1476465d084d062459ff437396a517facd37 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:28 +0100
Subject: [PATCH v2 4.12 15/17] xen: Use guest atomics helpers when modifying
 atomically guest memory

On Arm, exclusive load-store atomics should only be used between trusted
thread. As not all the guests are trusted, it may be possible to DoS Xen
when updating shared memory with guest atomically.

This patch replaces all the atomics operations on shared memory with
a guest by the new guest atomics helpers. The x86 code was not audited
to know where guest atomics helpers could be used. I will leave that
to the x86 folks.

Note that some rework was required in order to plumb use the new guest
atomics in event channel and grant-table.

Because guest_test_bit is ignoring the parameter "d" for now, it
means there a lot of places do not need to drop the const. We may want
to revisit this in the future if the parameter "d" becomes necessary.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/domain.c             |  3 +-
 xen/arch/arm/mm.c                 |  6 ++--
 xen/common/event_2l.c             | 26 ++++++++------
 xen/common/event_fifo.c           | 44 ++++++++++++-----------
 xen/common/grant_table.c          | 59 +++++++++++++++++--------------
 xen/include/asm-arm/grant_table.h |  2 +-
 xen/include/asm-x86/grant_table.h |  3 +-
 7 files changed, 79 insertions(+), 64 deletions(-)

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 6dc633ed50..c3d9d42ada 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -27,6 +27,7 @@
 #include <asm/event.h>
 #include <asm/gic.h>
 #include <asm/guest_access.h>
+#include <asm/guest_atomics.h>
 #include <asm/irq.h>
 #include <asm/p2m.h>
 #include <asm/platform.h>
@@ -1017,7 +1018,7 @@ void arch_dump_vcpu_info(struct vcpu *v)
 
 void vcpu_mark_events_pending(struct vcpu *v)
 {
-    int already_pending = test_and_set_bit(
+    bool already_pending = guest_test_and_set_bit(v->domain,
         0, (unsigned long *)&vcpu_info(v, evtchn_upcall_pending));
 
     if ( already_pending )
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 01ae2cccc0..3a7cfb1b50 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -40,6 +40,8 @@
 #include <xen/pfn.h>
 #include <xen/sizes.h>
 #include <xen/libfdt/libfdt.h>
+
+#include <asm/guest_atomics.h>
 #include <asm/setup.h>
 
 struct domain *dom_xen, *dom_io, *dom_cow;
@@ -1380,7 +1382,7 @@ void put_page_type(struct page_info *page)
     return;
 }
 
-void gnttab_clear_flag(unsigned long nr, uint16_t *addr)
+void gnttab_clear_flag(struct domain *d, unsigned long nr, uint16_t *addr)
 {
     /*
      * Note that this cannot be clear_bit(), as the access must be
@@ -1390,7 +1392,7 @@ void gnttab_clear_flag(unsigned long nr, uint16_t *addr)
 
     do {
         old = *addr;
-    } while (cmpxchg(addr, old, old & mask) != old);
+    } while (guest_cmpxchg(d, addr, old, old & mask) != old);
 }
 
 void gnttab_mark_dirty(struct domain *d, mfn_t mfn)
diff --git a/xen/common/event_2l.c b/xen/common/event_2l.c
index 8ca90899ab..e1dbb860f4 100644
--- a/xen/common/event_2l.c
+++ b/xen/common/event_2l.c
@@ -13,6 +13,8 @@
 #include <xen/sched.h>
 #include <xen/event.h>
 
+#include <asm/guest_atomics.h>
+
 static void evtchn_2l_set_pending(struct vcpu *v, struct evtchn *evtchn)
 {
     struct domain *d = v->domain;
@@ -25,12 +27,12 @@ static void evtchn_2l_set_pending(struct vcpu *v, struct evtchn *evtchn)
      * others may require explicit memory barriers.
      */
 
-    if ( test_and_set_bit(port, &shared_info(d, evtchn_pending)) )
+    if ( guest_test_and_set_bit(d, port, &shared_info(d, evtchn_pending)) )
         return;
 
-    if ( !test_bit        (port, &shared_info(d, evtchn_mask)) &&
-         !test_and_set_bit(port / BITS_PER_EVTCHN_WORD(d),
-                           &vcpu_info(v, evtchn_pending_sel)) )
+    if ( !guest_test_bit(d, port, &shared_info(d, evtchn_mask)) &&
+         !guest_test_and_set_bit(d, port / BITS_PER_EVTCHN_WORD(d),
+                                 &vcpu_info(v, evtchn_pending_sel)) )
     {
         vcpu_mark_events_pending(v);
     }
@@ -40,7 +42,7 @@ static void evtchn_2l_set_pending(struct vcpu *v, struct evtchn *evtchn)
 
 static void evtchn_2l_clear_pending(struct domain *d, struct evtchn *evtchn)
 {
-    clear_bit(evtchn->port, &shared_info(d, evtchn_pending));
+    guest_clear_bit(d, evtchn->port, &shared_info(d, evtchn_pending));
 }
 
 static void evtchn_2l_unmask(struct domain *d, struct evtchn *evtchn)
@@ -52,10 +54,10 @@ static void evtchn_2l_unmask(struct domain *d, struct evtchn *evtchn)
      * These operations must happen in strict order. Based on
      * evtchn_2l_set_pending() above.
      */
-    if ( test_and_clear_bit(port, &shared_info(d, evtchn_mask)) &&
-         test_bit          (port, &shared_info(d, evtchn_pending)) &&
-         !test_and_set_bit (port / BITS_PER_EVTCHN_WORD(d),
-                            &vcpu_info(v, evtchn_pending_sel)) )
+    if ( guest_test_and_clear_bit(d, port, &shared_info(d, evtchn_mask)) &&
+         guest_test_bit(d, port, &shared_info(d, evtchn_pending)) &&
+         !guest_test_and_set_bit(d, port / BITS_PER_EVTCHN_WORD(d),
+                                 &vcpu_info(v, evtchn_pending_sel)) )
     {
         vcpu_mark_events_pending(v);
     }
@@ -66,7 +68,8 @@ static bool evtchn_2l_is_pending(const struct domain *d, evtchn_port_t port)
     unsigned int max_ports = BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d);
 
     ASSERT(port < max_ports);
-    return port < max_ports && test_bit(port, &shared_info(d, evtchn_pending));
+    return (port < max_ports &&
+            guest_test_bit(d, port, &shared_info(d, evtchn_pending)));
 }
 
 static bool evtchn_2l_is_masked(const struct domain *d, evtchn_port_t port)
@@ -74,7 +77,8 @@ static bool evtchn_2l_is_masked(const struct domain *d, evtchn_port_t port)
     unsigned int max_ports = BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d);
 
     ASSERT(port < max_ports);
-    return port >= max_ports || test_bit(port, &shared_info(d, evtchn_mask));
+    return (port >= max_ports ||
+            guest_test_bit(d, port, &shared_info(d, evtchn_mask)));
 }
 
 static void evtchn_2l_print_state(struct domain *d,
diff --git a/xen/common/event_fifo.c b/xen/common/event_fifo.c
index 3eecab3f22..230f440f14 100644
--- a/xen/common/event_fifo.c
+++ b/xen/common/event_fifo.c
@@ -17,6 +17,8 @@
 #include <xen/mm.h>
 #include <xen/domain_page.h>
 
+#include <asm/guest_atomics.h>
+
 #include <public/event_channel.h>
 
 static inline event_word_t *evtchn_fifo_word_from_port(const struct domain *d,
@@ -51,7 +53,7 @@ static void evtchn_fifo_init(struct domain *d, struct evtchn *evtchn)
      * on the wrong VCPU or with an unexpected priority.
      */
     word = evtchn_fifo_word_from_port(d, evtchn->port);
-    if ( word && test_bit(EVTCHN_FIFO_LINKED, word) )
+    if ( word && guest_test_bit(d, EVTCHN_FIFO_LINKED, word) )
         gdprintk(XENLOG_WARNING, "domain %d, port %d already on a queue\n",
                  d->domain_id, evtchn->port);
 }
@@ -116,7 +118,7 @@ static int try_set_link(event_word_t *word, event_word_t *w, uint32_t link)
  * We block unmasking by the guest by marking the tail word as BUSY,
  * therefore, the cmpxchg() may fail at most 4 times.
  */
-static bool_t evtchn_fifo_set_link(const struct domain *d, event_word_t *word,
+static bool_t evtchn_fifo_set_link(struct domain *d, event_word_t *word,
                                    uint32_t link)
 {
     event_word_t w;
@@ -130,7 +132,7 @@ static bool_t evtchn_fifo_set_link(const struct domain *d, event_word_t *word,
         return ret;
 
     /* Lock the word to prevent guest unmasking. */
-    set_bit(EVTCHN_FIFO_BUSY, word);
+    guest_set_bit(d, EVTCHN_FIFO_BUSY, word);
 
     w = read_atomic(word);
 
@@ -140,13 +142,13 @@ static bool_t evtchn_fifo_set_link(const struct domain *d, event_word_t *word,
         if ( ret >= 0 )
         {
             if ( ret == 0 )
-                clear_bit(EVTCHN_FIFO_BUSY, word);
+                guest_clear_bit(d, EVTCHN_FIFO_BUSY, word);
             return ret;
         }
     }
     gdprintk(XENLOG_WARNING, "domain %d, port %d not linked\n",
              d->domain_id, link);
-    clear_bit(EVTCHN_FIFO_BUSY, word);
+    guest_clear_bit(d, EVTCHN_FIFO_BUSY, word);
     return 1;
 }
 
@@ -171,13 +173,13 @@ static void evtchn_fifo_set_pending(struct vcpu *v, struct evtchn *evtchn)
         return;
     }
 
-    was_pending = test_and_set_bit(EVTCHN_FIFO_PENDING, word);
+    was_pending = guest_test_and_set_bit(d, EVTCHN_FIFO_PENDING, word);
 
     /*
      * Link the event if it unmasked and not already linked.
      */
-    if ( !test_bit(EVTCHN_FIFO_MASKED, word)
-         && !test_bit(EVTCHN_FIFO_LINKED, word) )
+    if ( !guest_test_bit(d, EVTCHN_FIFO_MASKED, word) &&
+         !guest_test_bit(d, EVTCHN_FIFO_LINKED, word) )
     {
         struct evtchn_fifo_queue *q, *old_q;
         event_word_t *tail_word;
@@ -206,7 +208,7 @@ static void evtchn_fifo_set_pending(struct vcpu *v, struct evtchn *evtchn)
         if ( !old_q )
             goto done;
 
-        if ( test_and_set_bit(EVTCHN_FIFO_LINKED, word) )
+        if ( guest_test_and_set_bit(d, EVTCHN_FIFO_LINKED, word) )
         {
             spin_unlock_irqrestore(&old_q->lock, flags);
             goto done;
@@ -252,8 +254,8 @@ static void evtchn_fifo_set_pending(struct vcpu *v, struct evtchn *evtchn)
         spin_unlock_irqrestore(&q->lock, flags);
 
         if ( !linked
-             && !test_and_set_bit(q->priority,
-                                  &v->evtchn_fifo->control_block->ready) )
+             && !guest_test_and_set_bit(d, q->priority,
+                                        &v->evtchn_fifo->control_block->ready) )
             vcpu_mark_events_pending(v);
     }
  done:
@@ -275,7 +277,7 @@ static void evtchn_fifo_clear_pending(struct domain *d, struct evtchn *evtchn)
      * No need to unlink as the guest will unlink and ignore
      * non-pending events.
      */
-    clear_bit(EVTCHN_FIFO_PENDING, word);
+    guest_clear_bit(d, EVTCHN_FIFO_PENDING, word);
 }
 
 static void evtchn_fifo_unmask(struct domain *d, struct evtchn *evtchn)
@@ -287,10 +289,10 @@ static void evtchn_fifo_unmask(struct domain *d, struct evtchn *evtchn)
     if ( unlikely(!word) )
         return;
 
-    clear_bit(EVTCHN_FIFO_MASKED, word);
+    guest_clear_bit(d, EVTCHN_FIFO_MASKED, word);
 
     /* Relink if pending. */
-    if ( test_bit(EVTCHN_FIFO_PENDING, word) )
+    if ( guest_test_bit(d, EVTCHN_FIFO_PENDING, word) )
         evtchn_fifo_set_pending(v, evtchn);
 }
 
@@ -298,21 +300,21 @@ static bool evtchn_fifo_is_pending(const struct domain *d, evtchn_port_t port)
 {
     const event_word_t *word = evtchn_fifo_word_from_port(d, port);
 
-    return word && test_bit(EVTCHN_FIFO_PENDING, word);
+    return word && guest_test_bit(d, EVTCHN_FIFO_PENDING, word);
 }
 
 static bool_t evtchn_fifo_is_masked(const struct domain *d, evtchn_port_t port)
 {
     const event_word_t *word = evtchn_fifo_word_from_port(d, port);
 
-    return !word || test_bit(EVTCHN_FIFO_MASKED, word);
+    return !word || guest_test_bit(d, EVTCHN_FIFO_MASKED, word);
 }
 
 static bool_t evtchn_fifo_is_busy(const struct domain *d, evtchn_port_t port)
 {
     const event_word_t *word = evtchn_fifo_word_from_port(d, port);
 
-    return word && test_bit(EVTCHN_FIFO_LINKED, word);
+    return word && guest_test_bit(d, EVTCHN_FIFO_LINKED, word);
 }
 
 static int evtchn_fifo_set_priority(struct domain *d, struct evtchn *evtchn,
@@ -339,11 +341,11 @@ static void evtchn_fifo_print_state(struct domain *d,
     word = evtchn_fifo_word_from_port(d, evtchn->port);
     if ( !word )
         printk("?     ");
-    else if ( test_bit(EVTCHN_FIFO_LINKED, word) )
-        printk("%c %-4u", test_bit(EVTCHN_FIFO_BUSY, word) ? 'B' : ' ',
+    else if ( guest_test_bit(d, EVTCHN_FIFO_LINKED, word) )
+        printk("%c %-4u", guest_test_bit(d, EVTCHN_FIFO_BUSY, word) ? 'B' : ' ',
                *word & EVTCHN_FIFO_LINK_MASK);
     else
-        printk("%c -   ", test_bit(EVTCHN_FIFO_BUSY, word) ? 'B' : ' ');
+        printk("%c -   ", guest_test_bit(d, EVTCHN_FIFO_BUSY, word) ? 'B' : ' ');
 }
 
 static const struct evtchn_port_ops evtchn_port_ops_fifo =
@@ -495,7 +497,7 @@ static void setup_ports(struct domain *d)
 
         evtchn = evtchn_from_port(d, port);
 
-        if ( test_bit(port, &shared_info(d, evtchn_pending)) )
+        if ( guest_test_bit(d, port, &shared_info(d, evtchn_pending)) )
             evtchn->pending = 1;
 
         evtchn_fifo_set_priority(d, evtchn, EVTCHN_FIFO_PRIORITY_DEFAULT);
diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index 1b82d534a3..e9ce0ac473 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -39,6 +39,7 @@
 #include <xen/vmap.h>
 #include <xsm/xsm.h>
 #include <asm/flushtlb.h>
+#include <asm/guest_atomics.h>
 
 /* Per-domain grant information. */
 struct grant_table {
@@ -646,6 +647,7 @@ static unsigned int nr_grant_entries(struct grant_table *gt)
 }
 
 static int _set_status_v1(const grant_entry_header_t *shah,
+                          struct domain *rd,
                           struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
@@ -701,8 +703,8 @@ static int _set_status_v1(const grant_entry_header_t *shah,
                          "Attempt to write-pin a r/o grant entry\n");
         }
 
-        prev_scombo.word = cmpxchg((u32 *)shah,
-                                   scombo.word, new_scombo.word);
+        prev_scombo.word = guest_cmpxchg(rd, (u32 *)shah,
+                                         scombo.word, new_scombo.word);
         if ( likely(prev_scombo.word == scombo.word) )
             break;
 
@@ -719,6 +721,7 @@ done:
 
 static int _set_status_v2(const grant_entry_header_t *shah,
                           grant_status_t *status,
+                          struct domain *rd,
                           struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
@@ -781,8 +784,8 @@ static int _set_status_v2(const grant_entry_header_t *shah,
              (id != ldomid) ||
              (!readonly && (flags & GTF_readonly)) )
         {
-            gnttab_clear_flag(_GTF_writing, status);
-            gnttab_clear_flag(_GTF_reading, status);
+            gnttab_clear_flag(rd, _GTF_writing, status);
+            gnttab_clear_flag(rd, _GTF_reading, status);
             PIN_FAIL(done, GNTST_general_error,
                      "Unstable flags (%x) or dom (%d); expected d%d (r/w: %d)\n",
                      flags, id, ldomid, !readonly);
@@ -792,7 +795,7 @@ static int _set_status_v2(const grant_entry_header_t *shah,
     {
         if ( unlikely(flags & GTF_readonly) )
         {
-            gnttab_clear_flag(_GTF_writing, status);
+            gnttab_clear_flag(rd, _GTF_writing, status);
             PIN_FAIL(done, GNTST_general_error,
                      "Unstable grant readonly flag\n");
         }
@@ -805,6 +808,7 @@ done:
 
 static int _set_status(const grant_entry_header_t *shah,
                        grant_status_t *status,
+                       struct domain *rd,
                        unsigned rgt_version,
                        struct active_grant_entry *act,
                        int readonly,
@@ -813,9 +817,9 @@ static int _set_status(const grant_entry_header_t *shah,
 {
 
     if ( rgt_version == 1 )
-        return _set_status_v1(shah, act, readonly, mapflag, ldomid);
+        return _set_status_v1(shah, rd, act, readonly, mapflag, ldomid);
     else
-        return _set_status_v2(shah, status, act, readonly, mapflag, ldomid);
+        return _set_status_v2(shah, status, rd, act, readonly, mapflag, ldomid);
 }
 
 static struct active_grant_entry *grant_map_exists(const struct domain *ld,
@@ -980,7 +984,7 @@ map_grant_ref(
          (!(op->flags & GNTMAP_readonly) &&
           !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask))) )
     {
-        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+        if ( (rc = _set_status(shah, status, rd, rgt->gt_version, act,
                                op->flags & GNTMAP_readonly, 1,
                                ld->domain_id) != GNTST_okay) )
             goto act_release_out;
@@ -1204,10 +1208,10 @@ map_grant_ref(
  unlock_out_clear:
     if ( !(op->flags & GNTMAP_readonly) &&
          !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) )
-        gnttab_clear_flag(_GTF_writing, status);
+        gnttab_clear_flag(rd, _GTF_writing, status);
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 
  act_release_out:
     active_entry_release(act);
@@ -1477,10 +1481,10 @@ unmap_common_complete(struct gnttab_unmap_common *op)
 
     if ( ((act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0) &&
          !(op->done & GNTMAP_readonly) )
-        gnttab_clear_flag(_GTF_writing, status);
+        gnttab_clear_flag(rd, _GTF_writing, status);
 
     if ( act->pin == 0 )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 
     active_entry_release(act);
     grant_read_unlock(rgt);
@@ -2045,8 +2049,8 @@ gnttab_prepare_for_transfer(
         new_scombo = scombo;
         new_scombo.shorts.flags |= GTF_transfer_committed;
 
-        prev_scombo.word = cmpxchg((u32 *)&sha->flags,
-                                   scombo.word, new_scombo.word);
+        prev_scombo.word = guest_cmpxchg(rd, (u32 *)&sha->flags,
+                                         scombo.word, new_scombo.word);
         if ( likely(prev_scombo.word == scombo.word) )
             break;
 
@@ -2339,11 +2343,11 @@ release_grant_for_copy(
 
         act->pin -= GNTPIN_hstw_inc;
         if ( !(act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) )
-            gnttab_clear_flag(_GTF_writing, status);
+            gnttab_clear_flag(rd, _GTF_writing, status);
     }
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 
     active_entry_release(act);
     grant_read_unlock(rgt);
@@ -2365,14 +2369,15 @@ release_grant_for_copy(
    under the domain's grant table lock. */
 /* Only safe on transitive grants.  Even then, note that we don't
    attempt to drop any pin on the referent grant. */
-static void fixup_status_for_copy_pin(const struct active_grant_entry *act,
+static void fixup_status_for_copy_pin(struct domain *rd,
+                                      const struct active_grant_entry *act,
                                       uint16_t *status)
 {
     if ( !(act->pin & (GNTPIN_hstw_mask | GNTPIN_devw_mask)) )
-        gnttab_clear_flag(_GTF_writing, status);
+        gnttab_clear_flag(rd, _GTF_writing, status);
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 }
 
 /*
@@ -2434,7 +2439,7 @@ acquire_grant_for_copy(
     {
         if ( (!old_pin || (!readonly &&
                            !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)))) &&
-             (rc = _set_status_v2(shah, status, act, readonly, 0,
+             (rc = _set_status_v2(shah, status, rd, act, readonly, 0,
                                   ldom)) != GNTST_okay )
             goto unlock_out;
 
@@ -2483,7 +2488,7 @@ acquire_grant_for_copy(
 
         if ( rc != GNTST_okay )
         {
-            fixup_status_for_copy_pin(act, status);
+            fixup_status_for_copy_pin(rd, act, status);
             rcu_unlock_domain(td);
             active_entry_release(act);
             grant_read_unlock(rgt);
@@ -2506,7 +2511,7 @@ acquire_grant_for_copy(
                           !act->is_sub_page)) )
         {
             release_grant_for_copy(td, trans_gref, readonly);
-            fixup_status_for_copy_pin(act, status);
+            fixup_status_for_copy_pin(rd, act, status);
             rcu_unlock_domain(td);
             active_entry_release(act);
             grant_read_unlock(rgt);
@@ -2535,7 +2540,7 @@ acquire_grant_for_copy(
     else if ( !old_pin ||
               (!readonly && !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask))) )
     {
-        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+        if ( (rc = _set_status(shah, status, rd, rgt->gt_version, act,
                                readonly, 0, ldom)) != GNTST_okay )
              goto unlock_out;
 
@@ -2623,10 +2628,10 @@ acquire_grant_for_copy(
  unlock_out_clear:
     if ( !(readonly) &&
          !(act->pin & (GNTPIN_hstw_mask | GNTPIN_devw_mask)) )
-        gnttab_clear_flag(_GTF_writing, status);
+        gnttab_clear_flag(rd, _GTF_writing, status);
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, status);
+        gnttab_clear_flag(rd, _GTF_reading, status);
 
  unlock_out:
     active_entry_release(act);
@@ -3661,11 +3666,11 @@ gnttab_release_mappings(
             }
 
             if ( (act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0 )
-                gnttab_clear_flag(_GTF_writing, status);
+                gnttab_clear_flag(rd, _GTF_writing, status);
         }
 
         if ( act->pin == 0 )
-            gnttab_clear_flag(_GTF_reading, status);
+            gnttab_clear_flag(rd, _GTF_reading, status);
 
         active_entry_release(act);
         grant_read_unlock(rgt);
diff --git a/xen/include/asm-arm/grant_table.h b/xen/include/asm-arm/grant_table.h
index 816e3c6d68..5e9aa53814 100644
--- a/xen/include/asm-arm/grant_table.h
+++ b/xen/include/asm-arm/grant_table.h
@@ -14,7 +14,7 @@ struct grant_table_arch {
     gfn_t *status_gfn;
 };
 
-void gnttab_clear_flag(unsigned long nr, uint16_t *addr);
+void gnttab_clear_flag(struct domain *d, unsigned long nr, uint16_t *addr);
 int create_grant_host_mapping(unsigned long gpaddr, mfn_t mfn,
                               unsigned int flags, unsigned int cache_flags);
 #define gnttab_host_mapping_get_page_type(ro, ld, rd) (0)
diff --git a/xen/include/asm-x86/grant_table.h b/xen/include/asm-x86/grant_table.h
index 4b8c4f9160..11f061aa2d 100644
--- a/xen/include/asm-x86/grant_table.h
+++ b/xen/include/asm-x86/grant_table.h
@@ -64,7 +64,8 @@ static inline int replace_grant_host_mapping(uint64_t addr, mfn_t frame,
 
 #define gnttab_mark_dirty(d, f) paging_mark_dirty((d), f)
 
-static inline void gnttab_clear_flag(unsigned int nr, uint16_t *st)
+static inline void gnttab_clear_flag(struct domain *d, unsigned int nr,
+                                     uint16_t *st)
 {
     /*
      * Note that this cannot be clear_bit(), as the access must be
-- 
2.17.1
xsa295/4.12-16.patch (application/octet-stream, 4.1 KB)
From b5142d29a96d6c5bbd505d2ba299b1ef0416391a Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:29 +0100
Subject: [PATCH v2 4.12 16/17] xen/arm: Add performance counters in guest
 atomic helpers

Add performance counters in guest atomic helpers to be able to detect
whether a guest is often paused during the operations.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Acked-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/guest_atomics.h | 12 ++++++++++++
 xen/include/asm-arm/perfc_defn.h    |  3 +++
 2 files changed, 15 insertions(+)

diff --git a/xen/include/asm-arm/guest_atomics.h b/xen/include/asm-arm/guest_atomics.h
index 61925d313d..698508bf87 100644
--- a/xen/include/asm-arm/guest_atomics.h
+++ b/xen/include/asm-arm/guest_atomics.h
@@ -24,9 +24,13 @@ DECLARE_PER_CPU(unsigned int, guest_safe_atomic_max);
 #define guest_bitop(name)                                                   \
 static inline void guest_##name(struct domain *d, int nr, volatile void *p) \
 {                                                                           \
+    perfc_incr(atomics_guest);                                              \
+                                                                            \
     if ( name##_timeout(nr, p, this_cpu(guest_safe_atomic_max)) )           \
         return;                                                             \
                                                                             \
+    perfc_incr(atomics_guest_paused);                                       \
+                                                                            \
     domain_pause_nosync(d);                                                 \
     name(nr, p);                                                            \
     domain_unpause(d);                                                      \
@@ -38,11 +42,15 @@ static inline int guest_##name(struct domain *d, int nr, volatile void *p)  \
     bool succeed;                                                           \
     int oldbit;                                                             \
                                                                             \
+    perfc_incr(atomics_guest);                                              \
+                                                                            \
     succeed = name##_timeout(nr, p, &oldbit,                                \
                              this_cpu(guest_safe_atomic_max));              \
     if ( succeed )                                                          \
         return oldbit;                                                      \
                                                                             \
+    perfc_incr(atomics_guest_paused);                                       \
+                                                                            \
     domain_pause_nosync(d);                                                 \
     oldbit = name(nr, p);                                                   \
     domain_unpause(d);                                                      \
@@ -73,10 +81,14 @@ static inline unsigned long __guest_cmpxchg(struct domain *d,
 {
     unsigned long oldval = old;
 
+    perfc_incr(atomics_guest);
+
     if ( __cmpxchg_mb_timeout(ptr, &oldval, new, size,
                               this_cpu(guest_safe_atomic_max)) )
         return oldval;
 
+    perfc_incr(atomics_guest_paused);
+
     domain_pause_nosync(d);
     oldval = __cmpxchg_mb(ptr, old, new, size);
     domain_unpause(d);
diff --git a/xen/include/asm-arm/perfc_defn.h b/xen/include/asm-arm/perfc_defn.h
index 8922e9525a..6a83185163 100644
--- a/xen/include/asm-arm/perfc_defn.h
+++ b/xen/include/asm-arm/perfc_defn.h
@@ -73,6 +73,9 @@ PERFCOUNTER(phys_timer_irqs,  "Physical timer interrupts")
 PERFCOUNTER(virt_timer_irqs,  "Virtual timer interrupts")
 PERFCOUNTER(maintenance_irqs, "Maintenance interrupts")
 
+PERFCOUNTER(atomics_guest,    "atomics: guest access")
+PERFCOUNTER(atomics_guest_paused,   "atomics: guest paused")
+
 /*#endif*/ /* __XEN_PERFC_DEFN_H__ */
 
 /*
-- 
2.17.1
xsa295/4.12-17.patch (application/octet-stream, 6.4 KB)
From c338acb8b71b8aad258f4c3c0fda28ef294ed95c Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:30 +0100
Subject: [PATCH v2 4.12 17/17] xen/arm: grant-table: Protect gnttab_clear_flag
 against guest misbehavior

The function gnttab_clear_flag is used to clear the access flags. On
Arm, it is implemented using a loop and guest_cmpxchg.

It is possible that guest_cmpxchg will always return a different value
than old. This can happen if the guest updated the memory before Xen has
time to do the exchange. Because of that, there are no way for to
promise the loop will end.

It is possible to make the current code safe by re-using the same
principle as applied on the guest atomic helper. However this patch
takes a different approach that should lead to more efficient code in
the default case.

A new helper is introduced to clear a set of bits on a 16-bits word.
This should avoid a an extra loop to check cmpxchg succeeded.

Note that a mask is used instead of a bit, so the helper can be re-used
later on for clearing multiple flags at the same time.

This is part of XSA-295.

Reported-by: Andrew Cooper <[email protected]>
Signed-off-by: Julien Grall <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/arm32/lib/bitops.c     | 35 +++++++++++++++++++++++++++++
 xen/arch/arm/arm64/lib/bitops.c     | 33 +++++++++++++++++++++++++++
 xen/arch/arm/mm.c                   | 10 +--------
 xen/include/asm-arm/bitops.h        |  4 ++++
 xen/include/asm-arm/guest_atomics.h | 13 +++++++++++
 5 files changed, 86 insertions(+), 9 deletions(-)

diff --git a/xen/arch/arm/arm32/lib/bitops.c b/xen/arch/arm/arm32/lib/bitops.c
index 08750314fc..3dca769bf0 100644
--- a/xen/arch/arm/arm32/lib/bitops.c
+++ b/xen/arch/arm/arm32/lib/bitops.c
@@ -126,6 +126,41 @@ testop(test_and_change_bit, eor)
 testop(test_and_clear_bit, bic)
 testop(test_and_set_bit, orr)
 
+static always_inline bool int_clear_mask16(uint16_t mask, volatile uint16_t *p,
+                                           bool timeout, unsigned int max_try)
+{
+    unsigned long res, tmp;
+
+    prefetchw((const uint16_t *)p);
+
+    do
+    {
+        asm volatile ("// int_clear_mask16\n"
+        "   ldrexh  %2, %1\n"
+        "   bic     %2, %2, %3\n"
+        "   strexh  %0, %2, %1\n"
+        : "=&r" (res), "+Qo" (*p), "=&r" (tmp)
+        : "r" (mask));
+
+        if ( !res )
+            break;
+    } while ( !timeout || ((--max_try) > 0) );
+
+    return !res;
+}
+
+void clear_mask16(uint16_t mask, volatile void *p)
+{
+    if ( !int_clear_mask16(mask, p, false, 0) )
+        ASSERT_UNREACHABLE();
+}
+
+bool clear_mask16_timeout(uint16_t mask, volatile void *p,
+                          unsigned int max_try)
+{
+    return int_clear_mask16(mask, p, true, max_try);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
index 78bf4ed8c5..27688e5418 100644
--- a/xen/arch/arm/arm64/lib/bitops.c
+++ b/xen/arch/arm/arm64/lib/bitops.c
@@ -118,6 +118,39 @@ testop(test_and_change_bit, eor)
 testop(test_and_clear_bit, bic)
 testop(test_and_set_bit, orr)
 
+static always_inline bool int_clear_mask16(uint16_t mask, volatile uint16_t *p,
+                                           bool timeout, unsigned int max_try)
+{
+    unsigned long res, tmp;
+
+    do
+    {
+        asm volatile ("//  int_clear_mask16\n"
+        "   ldxrh   %w2, %1\n"
+        "   bic     %w2, %w2, %w3\n"
+        "   stxrh   %w0, %w2, %1\n"
+        : "=&r" (res), "+Q" (*p), "=&r" (tmp)
+        : "r" (mask));
+
+        if ( !res )
+            break;
+    } while ( !timeout || ((--max_try) > 0) );
+
+    return !res;
+}
+
+void clear_mask16(uint16_t mask, volatile void *p)
+{
+    if ( !int_clear_mask16(mask, p, false, 0) )
+        ASSERT_UNREACHABLE();
+}
+
+bool clear_mask16_timeout(uint16_t mask, volatile void *p,
+                          unsigned int max_try)
+{
+    return int_clear_mask16(mask, p, true, max_try);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 3a7cfb1b50..8a53544975 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -1384,15 +1384,7 @@ void put_page_type(struct page_info *page)
 
 void gnttab_clear_flag(struct domain *d, unsigned long nr, uint16_t *addr)
 {
-    /*
-     * Note that this cannot be clear_bit(), as the access must be
-     * confined to the specified 2 bytes.
-     */
-    uint16_t mask = ~(1 << nr), old;
-
-    do {
-        old = *addr;
-    } while (guest_cmpxchg(d, addr, old, old & mask) != old);
+    guest_clear_mask16(d, BIT(nr), addr);
 }
 
 void gnttab_mark_dirty(struct domain *d, mfn_t mfn)
diff --git a/xen/include/asm-arm/bitops.h b/xen/include/asm-arm/bitops.h
index f6782b33be..f989bc726c 100644
--- a/xen/include/asm-arm/bitops.h
+++ b/xen/include/asm-arm/bitops.h
@@ -53,6 +53,8 @@ int test_and_set_bit(int nr, volatile void *p);
 int test_and_clear_bit(int nr, volatile void *p);
 int test_and_change_bit(int nr, volatile void *p);
 
+void clear_mask16(uint16_t mask, volatile void *p);
+
 /*
  * The helpers below may fail to update the memory if the action takes
  * too long.
@@ -71,6 +73,8 @@ bool test_and_clear_bit_timeout(int nr, volatile void *p,
                                 int *oldbit, unsigned int max_try);
 bool test_and_change_bit_timeout(int nr, volatile void *p,
                                  int *oldbit, unsigned int max_try);
+bool clear_mask16_timeout(uint16_t mask, volatile void *p,
+                          unsigned int max_try);
 
 /**
  * __test_and_set_bit - Set a bit and return its old value
diff --git a/xen/include/asm-arm/guest_atomics.h b/xen/include/asm-arm/guest_atomics.h
index 698508bf87..af27cc627b 100644
--- a/xen/include/asm-arm/guest_atomics.h
+++ b/xen/include/asm-arm/guest_atomics.h
@@ -73,6 +73,19 @@ guest_testop(test_and_change_bit)
 
 #undef guest_testop
 
+static inline void guest_clear_mask16(struct domain *d, uint16_t mask,
+                                      volatile uint16_t *p)
+{
+    perfc_incr(atomics_guest);
+
+    if ( clear_mask16_timeout(mask, p, this_cpu(guest_safe_atomic_max)) )
+        return;
+
+    domain_pause_nosync(d);
+    clear_mask16(mask, p);
+    domain_unpause(d);
+}
+
 static inline unsigned long __guest_cmpxchg(struct domain *d,
                                             volatile void *ptr,
                                             unsigned long old,
-- 
2.17.1
xsa295/unstable-01.patch (application/octet-stream, 2 KB)
From 0feb42494feddf4d140d83aa417d8d7bf3c50f53 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:16 +0100
Subject: [PATCH 01/15] xen/arm: Add an isb() before reading CNTPCT_EL0 to
 prevent re-ordering

Per D8.2.1 in ARM DDI 0487C.a, "a read to CNTPCT_EL0 can occur
speculatively and out of order relative to other instructions executed
on the same PE."

Add an instruction barrier to get accurate number of cycles when
requested in get_cycles(). For the other users of CNPCT_EL0, replace by
a call to get_cycles().

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Acked-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/time.c        | 4 ++--
 xen/include/asm-arm/time.h | 2 ++
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/time.c b/xen/arch/arm/time.c
index bbccee742e..739bcf186c 100644
--- a/xen/arch/arm/time.c
+++ b/xen/arch/arm/time.c
@@ -151,7 +151,7 @@ void __init preinit_xen_time(void)
     if ( res )
         panic("Timer: Cannot initialize platform timer\n");
 
-    boot_count = READ_SYSREG64(CNTPCT_EL0);
+    boot_count = get_cycles();
 }
 
 static void __init init_dt_xen_time(void)
@@ -192,7 +192,7 @@ int __init init_xen_time(void)
 /* Return number of nanoseconds since boot */
 s_time_t get_s_time(void)
 {
-    uint64_t ticks = READ_SYSREG64(CNTPCT_EL0) - boot_count;
+    uint64_t ticks = get_cycles() - boot_count;
     return ticks_to_ns(ticks);
 }
 
diff --git a/xen/include/asm-arm/time.h b/xen/include/asm-arm/time.h
index 9a7071a546..9cb6f9b0b4 100644
--- a/xen/include/asm-arm/time.h
+++ b/xen/include/asm-arm/time.h
@@ -2,6 +2,7 @@
 #define __ARM_TIME_H__
 
 #include <asm/sysregs.h>
+#include <asm/system.h>
 
 #define DT_MATCH_TIMER                      \
     DT_MATCH_COMPATIBLE("arm,armv7-timer"), \
@@ -11,6 +12,7 @@ typedef uint64_t cycles_t;
 
 static inline cycles_t get_cycles (void)
 {
+        isb();
         return READ_SYSREG64(CNTPCT_EL0);
 }
 
-- 
2.11.0
xsa295/unstable-02.patch (application/octet-stream, 6.6 KB)
From 95f9529337e7cdff2560ea486561db4ad89256c1 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:17 +0100
Subject: [PATCH 02/15] xen/grant_table: Rework the prototype of _set_status*
 for lisibility

It is not clear from the parameters name whether domid and gt_version
correspond to the local or remote domain. A follow-up patch will make
them more confusing.

So rename domid (resp. gt_version) to ldomid (resp. rgt_version). At
the same time re-order the parameters to hopefully make it more
readable.

This is part of XSA-295.

Suggested-by: Jan Beulich <[email protected]>
Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Jan Beulich <[email protected]>
Acked-by: Stefano Stabellini <[email protected]>
---
 xen/common/grant_table.c | 57 ++++++++++++++++++++++++------------------------
 1 file changed, 28 insertions(+), 29 deletions(-)

diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index dd8a9d9046..6ec556cb85 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -670,11 +670,11 @@ static unsigned int nr_grant_entries(struct grant_table *gt)
     return 0;
 }
 
-static int _set_status_v1(domid_t  domid,
+static int _set_status_v1(const grant_entry_header_t *shah,
+                          struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
-                          grant_entry_header_t *shah,
-                          struct active_grant_entry *act)
+                          domid_t  ldomid)
 {
     int rc = GNTST_okay;
     union grant_combo scombo, prev_scombo, new_scombo;
@@ -709,11 +709,11 @@ static int _set_status_v1(domid_t  domid,
         if ( !act->pin &&
              (((scombo.shorts.flags & mask) !=
                GTF_permit_access) ||
-              (scombo.shorts.domid != domid)) )
+              (scombo.shorts.domid != ldomid)) )
             PIN_FAIL(done, GNTST_general_error,
                      "Bad flags (%x) or dom (%d); expected d%d\n",
                      scombo.shorts.flags, scombo.shorts.domid,
-                     domid);
+                     ldomid);
 
         new_scombo = scombo;
         new_scombo.shorts.flags |= GTF_reading;
@@ -742,12 +742,12 @@ done:
     return rc;
 }
 
-static int _set_status_v2(domid_t  domid,
+static int _set_status_v2(const grant_entry_header_t *shah,
+                          grant_status_t *status,
+                          struct active_grant_entry *act,
                           int readonly,
                           int mapflag,
-                          grant_entry_header_t *shah,
-                          struct active_grant_entry *act,
-                          grant_status_t *status)
+                          domid_t  ldomid)
 {
     int      rc    = GNTST_okay;
     union grant_combo scombo;
@@ -773,10 +773,10 @@ static int _set_status_v2(domid_t  domid,
     if ( !act->pin &&
          ( (((flags & mask) != GTF_permit_access) &&
             ((flags & mask) != GTF_transitive)) ||
-          (id != domid)) )
+          (id != ldomid)) )
         PIN_FAIL(done, GNTST_general_error,
                  "Bad flags (%x) or dom (%d); expected d%d, flags %x\n",
-                 flags, id, domid, mask);
+                 flags, id, ldomid, mask);
 
     if ( readonly )
     {
@@ -803,14 +803,14 @@ static int _set_status_v2(domid_t  domid,
     {
         if ( (((flags & mask) != GTF_permit_access) &&
               ((flags & mask) != GTF_transitive)) ||
-             (id != domid) ||
+             (id != ldomid) ||
              (!readonly && (flags & GTF_readonly)) )
         {
             gnttab_clear_flag(_GTF_writing, status);
             gnttab_clear_flag(_GTF_reading, status);
             PIN_FAIL(done, GNTST_general_error,
                      "Unstable flags (%x) or dom (%d); expected d%d (r/w: %d)\n",
-                     flags, id, domid, !readonly);
+                     flags, id, ldomid, !readonly);
         }
     }
     else
@@ -828,19 +828,19 @@ done:
 }
 
 
-static int _set_status(unsigned gt_version,
-                       domid_t  domid,
+static int _set_status(const grant_entry_header_t *shah,
+                       grant_status_t *status,
+                       unsigned rgt_version,
+                       struct active_grant_entry *act,
                        int readonly,
                        int mapflag,
-                       grant_entry_header_t *shah,
-                       struct active_grant_entry *act,
-                       grant_status_t *status)
+                       domid_t ldomid)
 {
 
-    if ( gt_version == 1 )
-        return _set_status_v1(domid, readonly, mapflag, shah, act);
+    if ( rgt_version == 1 )
+        return _set_status_v1(shah, act, readonly, mapflag, ldomid);
     else
-        return _set_status_v2(domid, readonly, mapflag, shah, act, status);
+        return _set_status_v2(shah, status, act, readonly, mapflag, ldomid);
 }
 
 static struct active_grant_entry *grant_map_exists(const struct domain *ld,
@@ -1005,9 +1005,9 @@ map_grant_ref(
          (!(op->flags & GNTMAP_readonly) &&
           !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask))) )
     {
-        if ( (rc = _set_status(rgt->gt_version, ld->domain_id,
-                               op->flags & GNTMAP_readonly,
-                               1, shah, act, status) ) != GNTST_okay )
+        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+                               op->flags & GNTMAP_readonly, 1,
+                               ld->domain_id) != GNTST_okay) )
             goto act_release_out;
 
         if ( !act->pin )
@@ -2459,8 +2459,8 @@ acquire_grant_for_copy(
     {
         if ( (!old_pin || (!readonly &&
                            !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)))) &&
-             (rc = _set_status_v2(ldom, readonly, 0, shah, act,
-                                  status)) != GNTST_okay )
+             (rc = _set_status_v2(shah, status, act, readonly, 0,
+                                  ldom)) != GNTST_okay )
             goto unlock_out;
 
         if ( !allow_transitive )
@@ -2560,9 +2560,8 @@ acquire_grant_for_copy(
     else if ( !old_pin ||
               (!readonly && !(old_pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask))) )
     {
-        if ( (rc = _set_status(rgt->gt_version, ldom,
-                               readonly, 0, shah, act,
-                               status) ) != GNTST_okay )
+        if ( (rc = _set_status(shah, status, rgt->gt_version, act,
+                               readonly, 0, ldom)) != GNTST_okay )
              goto unlock_out;
 
         td = rd;
-- 
2.11.0
xsa295/unstable-03.patch (application/octet-stream, 7.8 KB)
From 432caefb7b8b676965b35e12a6d5d5d676aa8943 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:18 +0100
Subject: [PATCH 03/15] xen/arm64: bitops: Rewrite bitop helpers in C

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/README.LinuxPrimitives |  1 -
 xen/arch/arm/arm64/lib/bitops.S     | 67 ---------------------------
 xen/arch/arm/arm64/lib/bitops.c     | 90 +++++++++++++++++++++++++++++++++++++
 3 files changed, 90 insertions(+), 68 deletions(-)
 delete mode 100644 xen/arch/arm/arm64/lib/bitops.S
 create mode 100644 xen/arch/arm/arm64/lib/bitops.c

diff --git a/xen/arch/arm/README.LinuxPrimitives b/xen/arch/arm/README.LinuxPrimitives
index 028e8721f9..891667a5da 100644
--- a/xen/arch/arm/README.LinuxPrimitives
+++ b/xen/arch/arm/README.LinuxPrimitives
@@ -8,7 +8,6 @@ arm64:
 
 bitops: last sync @ v3.16-rc6 (last commit: 8715466b6027)
 
-linux/arch/arm64/lib/bitops.S           xen/arch/arm/arm64/lib/bitops.S
 linux/arch/arm64/include/asm/bitops.h   xen/include/asm-arm/arm64/bitops.h
 
 ---------------------------------------------------------------------
diff --git a/xen/arch/arm/arm64/lib/bitops.S b/xen/arch/arm/arm64/lib/bitops.S
deleted file mode 100644
index 6471dd1875..0000000000
--- a/xen/arch/arm/arm64/lib/bitops.S
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Based on linux/arch/arm64/lib/bitops.h which in turn is
- * Based on arch/arm/lib/bitops.h
- *
- * Copyright (C) 2013 ARM Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * x0: bits 4:0  bit offset
- *     bits 31:5 word offset
- * x1: address
- */
-	.macro	bitop, name, instr
-ENTRY(	\name	)
-	and	w3, w0, #31		// Get bit offset
-	eor	w0, w0, w3		// Clear low bits
-	mov	x2, #1
-	add	x1, x1, x0, lsr #3	// Get word offset
-	lsl	x3, x2, x3		// Create mask
-1:	ldxr	w2, [x1]
-	\instr	w2, w2, w3
-	stxr	w0, w2, [x1]
-	cbnz	w0, 1b
-	ret
-ENDPROC(\name	)
-	.endm
-
-	.macro	testop, name, instr
-ENTRY(	\name	)
-	and	w3, w0, #31		// Get bit offset
-	eor	w0, w0, w3		// Clear low bits
-	mov	x2, #1
-	add	x1, x1, x0, lsr #3	// Get word offset
-	lsl	x4, x2, x3		// Create mask
-1:	ldxr	w2, [x1]
-	lsr	w0, w2, w3		// Save old value of bit
-	\instr	w2, w2, w4		// toggle bit
-	stlxr	w5, w2, [x1]
-	cbnz	w5, 1b
-	dmb	ish
-	and	w0, w0, #1
-3:	ret
-ENDPROC(\name	)
-	.endm
-
-/*
- * Atomic bit operations.
- */
-	bitop	change_bit, eor
-	bitop	clear_bit, bic
-	bitop	set_bit, orr
-
-	testop	test_and_change_bit, eor
-	testop	test_and_clear_bit, bic
-	testop	test_and_set_bit, orr
diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
new file mode 100644
index 0000000000..b1c681c642
--- /dev/null
+++ b/xen/arch/arm/arm64/lib/bitops.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/bitops.h>
+#include <asm/system.h>
+
+/*
+ * The atomic bit operations pass the number of bit in a signed number
+ * (not sure why). This has the drawback to increase the complexity of
+ * the resulting assembly.
+ *
+ * To generate simpler code, the number of bit (nr) will be cast to
+ * unsigned int.
+ *
+ * XXX: Rework the interface to use unsigned int.
+ */
+
+#define bitop(name, instr)                                                  \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
+    unsigned long res, tmp;                                                 \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldxr    %w2, %1\n"                                              \
+        "   " __stringify(instr) "     %w2, %w2, %w3\n"                     \
+        "   stxr    %w0, %w2, %1\n"                                         \
+        : "=&r" (res), "+Q" (*ptr), "=&r" (tmp)                             \
+        : "r" (mask));                                                      \
+    } while ( res );                                                        \
+}                                                                           \
+
+#define testop(name, instr)                                                 \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
+    const uint32_t mask = BIT_MASK(bit);                                    \
+    unsigned long res, tmp;                                                 \
+    unsigned long oldbit;                                                   \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldxr    %w3, %2\n"                                              \
+        "   lsr     %w1, %w3, %w5 // Save old value of bit\n"               \
+        "   " __stringify(instr) "  %w3, %w3, %w4 // Toggle bit\n"          \
+        "   stlxr   %w0, %w3, %2\n"                                         \
+        : "=&r" (res), "=&r" (oldbit), "+Q" (*ptr), "=&r" (tmp)             \
+        : "r" (mask), "r" (bit)                                             \
+        : "memory");                                                        \
+    } while ( res );                                                        \
+                                                                            \
+    dmb(ish);                                                               \
+                                                                            \
+    return oldbit & 1;                                                      \
+}
+
+bitop(change_bit, eor)
+bitop(clear_bit, bic)
+bitop(set_bit, orr)
+
+testop(test_and_change_bit, eor)
+testop(test_and_clear_bit, bic)
+testop(test_and_set_bit, orr)
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.11.0
xsa295/unstable-04.patch (application/octet-stream, 15.6 KB)
From 624b86f04e8ee67bac38d2451c8cd6479a5b420c Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:19 +0100
Subject: [PATCH 04/15] xen/arm32: bitops: Rewrite bitop helpers in C

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/README.LinuxPrimitives    |  14 +----
 xen/arch/arm/arm32/lib/Makefile        |   5 +-
 xen/arch/arm/arm32/lib/bitops.c        |  98 +++++++++++++++++++++++++++++++
 xen/arch/arm/arm32/lib/bitops.h        | 104 ---------------------------------
 xen/arch/arm/arm32/lib/changebit.S     |  14 -----
 xen/arch/arm/arm32/lib/clearbit.S      |  14 -----
 xen/arch/arm/arm32/lib/setbit.S        |  15 -----
 xen/arch/arm/arm32/lib/testchangebit.S |  15 -----
 xen/arch/arm/arm32/lib/testclearbit.S  |  15 -----
 xen/arch/arm/arm32/lib/testsetbit.S    |  15 -----
 xen/include/asm-arm/arm32/bitops.h     |  19 ++----
 11 files changed, 108 insertions(+), 220 deletions(-)
 create mode 100644 xen/arch/arm/arm32/lib/bitops.c
 delete mode 100644 xen/arch/arm/arm32/lib/bitops.h
 delete mode 100644 xen/arch/arm/arm32/lib/changebit.S
 delete mode 100644 xen/arch/arm/arm32/lib/clearbit.S
 delete mode 100644 xen/arch/arm/arm32/lib/setbit.S
 delete mode 100644 xen/arch/arm/arm32/lib/testchangebit.S
 delete mode 100644 xen/arch/arm/arm32/lib/testclearbit.S
 delete mode 100644 xen/arch/arm/arm32/lib/testsetbit.S

diff --git a/xen/arch/arm/README.LinuxPrimitives b/xen/arch/arm/README.LinuxPrimitives
index 891667a5da..664a9f89ed 100644
--- a/xen/arch/arm/README.LinuxPrimitives
+++ b/xen/arch/arm/README.LinuxPrimitives
@@ -68,19 +68,9 @@ arm32
 
 bitops: last sync @ v3.16-rc6 (last commit: c32ffce0f66e)
 
-linux/arch/arm/lib/bitops.h             xen/arch/arm/arm32/lib/bitops.h
-linux/arch/arm/lib/changebit.S          xen/arch/arm/arm32/lib/changebit.S
-linux/arch/arm/lib/clearbit.S           xen/arch/arm/arm32/lib/clearbit.S
 linux/arch/arm/lib/findbit.S            xen/arch/arm/arm32/lib/findbit.S
-linux/arch/arm/lib/setbit.S             xen/arch/arm/arm32/lib/setbit.S
-linux/arch/arm/lib/testchangebit.S      xen/arch/arm/arm32/lib/testchangebit.S
-linux/arch/arm/lib/testclearbit.S       xen/arch/arm/arm32/lib/testclearbit.S
-linux/arch/arm/lib/testsetbit.S         xen/arch/arm/arm32/lib/testsetbit.S
-
-for i in bitops.h changebit.S clearbit.S findbit.S setbit.S testchangebit.S \
-         testclearbit.S testsetbit.S; do
-    diff -u ../linux/arch/arm/lib/$i xen/arch/arm/arm32/lib/$i;
-done
+
+diff -u ../linux/arch/arm/lib/findbit.S xen/arch/arm/arm32/lib/findbit.S
 
 ---------------------------------------------------------------------
 
diff --git a/xen/arch/arm/arm32/lib/Makefile b/xen/arch/arm/arm32/lib/Makefile
index e9fbc595b9..b1457c89dc 100644
--- a/xen/arch/arm/arm32/lib/Makefile
+++ b/xen/arch/arm/arm32/lib/Makefile
@@ -1,6 +1,5 @@
 obj-y += memcpy.o memmove.o memset.o memchr.o memzero.o
-obj-y += findbit.o setbit.o
-obj-y += setbit.o clearbit.o changebit.o
-obj-y += testsetbit.o testclearbit.o testchangebit.o
+obj-y += findbit.o
+obj-y += bitops.o
 obj-y += strchr.o strrchr.o
 obj-y += lib1funcs.o lshrdi3.o div64.o
diff --git a/xen/arch/arm/arm32/lib/bitops.c b/xen/arch/arm/arm32/lib/bitops.c
new file mode 100644
index 0000000000..c69bb53037
--- /dev/null
+++ b/xen/arch/arm/arm32/lib/bitops.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/bitops.h>
+#include <xen/prefetch.h>
+#include <asm/system.h>
+
+/*
+ * The atomic bit operations pass the number of bit in a signed number
+ * (not sure why). This has the drawback to increase the complexity of
+ * the resulting assembly.
+ *
+ * To generate simpler code, the number of bit (nr) will be cast to
+ * unsigned int.
+ *
+ * XXX: Rework the interface to use unsigned int.
+ */
+
+#define bitop(name, instr)                                                  \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
+    unsigned long res, tmp;                                                 \
+                                                                            \
+    ASSERT(((vaddr_t)p & 0x3) == 0);                                        \
+    prefetchw((const void *)ptr);                                           \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldrex   %2, %1\n"                                               \
+        "   " __stringify(instr) "     %2, %2, %3\n"                        \
+        "   strex   %0, %2, %1\n"                                           \
+        : "=&r" (res), "+Qo" (*ptr), "=&r" (tmp)                            \
+        : "r" (mask));                                                      \
+    } while ( res );                                                        \
+}
+
+#define testop(name, instr)                                                 \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
+    unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
+    const uint32_t mask = BIT_MASK(bit);                                    \
+    unsigned long res, tmp;                                                 \
+    int oldbit;                                                             \
+                                                                            \
+    ASSERT(((vaddr_t)p & 0x3) == 0);                                        \
+    smp_mb();                                                               \
+                                                                            \
+    prefetchw((const void *)ptr);                                           \
+                                                                            \
+    do                                                                      \
+    {                                                                       \
+        asm volatile ("// " __stringify(name) "\n"                          \
+        "   ldrex   %3, %2\n"                                               \
+        "   lsr     %1, %3, %5 // Save old value of bit\n"                  \
+        "   " __stringify(instr) "  %3, %3, %4 // Toggle bit\n"             \
+        "   strex  %0, %3, %2\n"                                            \
+        : "=&r" (res), "=&r" (oldbit), "+Qo" (*ptr), "=&r" (tmp)            \
+        : "r" (mask), "r" (bit));                                           \
+    } while ( res );                                                        \
+                                                                            \
+    smp_mb();                                                               \
+                                                                            \
+    return oldbit & 1;                                                      \
+}                                                                           \
+
+bitop(change_bit, eor)
+bitop(clear_bit, bic)
+bitop(set_bit, orr)
+
+testop(test_and_change_bit, eor)
+testop(test_and_clear_bit, bic)
+testop(test_and_set_bit, orr)
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/arm32/lib/bitops.h b/xen/arch/arm/arm32/lib/bitops.h
deleted file mode 100644
index d5e13476f4..0000000000
--- a/xen/arch/arm/arm32/lib/bitops.h
+++ /dev/null
@@ -1,104 +0,0 @@
-
-#if __LINUX_ARM_ARCH__ >= 6
-	.macro	bitop, name, instr
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	mov	r2, #1
-	and	r3, r0, #31		@ Get bit offset
-	mov	r0, r0, lsr #5
-	add	r1, r1, r0, lsl #2	@ Get word offset
-#if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
-	.arch_extension	mp
-	ALT_SMP(W(pldw)	[r1])
-	ALT_UP(W(nop))
-#endif
-	mov	r3, r2, lsl r3
-1:	ldrex	r2, [r1]
-	\instr	r2, r2, r3
-	strex	r0, r2, [r1]
-	cmp	r0, #0
-	bne	1b
-	bx	lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-
-	.macro	testop, name, instr, store
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	mov	r2, #1
-	and	r3, r0, #31		@ Get bit offset
-	mov	r0, r0, lsr #5
-	add	r1, r1, r0, lsl #2	@ Get word offset
-	mov	r3, r2, lsl r3		@ create mask
-	smp_dmb
-#if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
-	.arch_extension	mp
-	ALT_SMP(W(pldw)	[r1])
-	ALT_UP(W(nop))
-#endif
-1:	ldrex	r2, [r1]
-	ands	r0, r2, r3		@ save old value of bit
-	\instr	r2, r2, r3		@ toggle bit
-	strex	ip, r2, [r1]
-	cmp	ip, #0
-	bne	1b
-	smp_dmb
-	cmp	r0, #0
-	movne	r0, #1
-2:	bx	lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-#else
-	.macro	bitop, name, instr
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	and	r2, r0, #31
-	mov	r0, r0, lsr #5
-	mov	r3, #1
-	mov	r3, r3, lsl r2
-	save_and_disable_irqs ip
-	ldr	r2, [r1, r0, lsl #2]
-	\instr	r2, r2, r3
-	str	r2, [r1, r0, lsl #2]
-	restore_irqs ip
-	mov	pc, lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-
-/**
- * testop - implement a test_and_xxx_bit operation.
- * @instr: operational instruction
- * @store: store instruction
- *
- * Note: we can trivially conditionalise the store instruction
- * to avoid dirtying the data cache.
- */
-	.macro	testop, name, instr, store
-ENTRY(	\name		)
-UNWIND(	.fnstart	)
-	ands	ip, r1, #3
-	strneb	r1, [ip]		@ assert word-aligned
-	and	r3, r0, #31
-	mov	r0, r0, lsr #5
-	save_and_disable_irqs ip
-	ldr	r2, [r1, r0, lsl #2]!
-	mov	r0, #1
-	tst	r2, r0, lsl r3
-	\instr	r2, r2, r0, lsl r3
-	\store	r2, [r1]
-	moveq	r0, #0
-	restore_irqs ip
-	mov	pc, lr
-UNWIND(	.fnend		)
-ENDPROC(\name		)
-	.endm
-#endif
diff --git a/xen/arch/arm/arm32/lib/changebit.S b/xen/arch/arm/arm32/lib/changebit.S
deleted file mode 100644
index 6e4ae7594a..0000000000
--- a/xen/arch/arm/arm32/lib/changebit.S
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- *  linux/arch/arm/lib/changebit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-bitop	_change_bit, eor
diff --git a/xen/arch/arm/arm32/lib/clearbit.S b/xen/arch/arm/arm32/lib/clearbit.S
deleted file mode 100644
index fda553f246..0000000000
--- a/xen/arch/arm/arm32/lib/clearbit.S
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- *  linux/arch/arm/lib/clearbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-bitop	_clear_bit, bic
diff --git a/xen/arch/arm/arm32/lib/setbit.S b/xen/arch/arm/arm32/lib/setbit.S
deleted file mode 100644
index d52f0ab65c..0000000000
--- a/xen/arch/arm/arm32/lib/setbit.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- *  linux/arch/arm/lib/setbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "assembler.h"
-#include "bitops.h"
-	.text
-
-bitop	_set_bit, orr
diff --git a/xen/arch/arm/arm32/lib/testchangebit.S b/xen/arch/arm/arm32/lib/testchangebit.S
deleted file mode 100644
index d83b04c057..0000000000
--- a/xen/arch/arm/arm32/lib/testchangebit.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- *  linux/arch/arm/lib/testchangebit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-testop	_test_and_change_bit, eor, str
diff --git a/xen/arch/arm/arm32/lib/testclearbit.S b/xen/arch/arm/arm32/lib/testclearbit.S
deleted file mode 100644
index 6f5b7b92d1..0000000000
--- a/xen/arch/arm/arm32/lib/testclearbit.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- *  linux/arch/arm/lib/testclearbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-testop	_test_and_clear_bit, bicne, strne
diff --git a/xen/arch/arm/arm32/lib/testsetbit.S b/xen/arch/arm/arm32/lib/testsetbit.S
deleted file mode 100644
index 30425a842a..0000000000
--- a/xen/arch/arm/arm32/lib/testsetbit.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- *  linux/arch/arm/lib/testsetbit.S
- *
- *  Copyright (C) 1995-1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "assembler.h"
-#include "bitops.h"
-                .text
-
-testop	_test_and_set_bit, orreq, streq
diff --git a/xen/include/asm-arm/arm32/bitops.h b/xen/include/asm-arm/arm32/bitops.h
index 8be3564540..67c4c3f55c 100644
--- a/xen/include/asm-arm/arm32/bitops.h
+++ b/xen/include/asm-arm/arm32/bitops.h
@@ -1,19 +1,12 @@
 #ifndef _ARM_ARM32_BITOPS_H
 #define _ARM_ARM32_BITOPS_H
 
-extern void _set_bit(int nr, volatile void * p);
-extern void _clear_bit(int nr, volatile void * p);
-extern void _change_bit(int nr, volatile void * p);
-extern int _test_and_set_bit(int nr, volatile void * p);
-extern int _test_and_clear_bit(int nr, volatile void * p);
-extern int _test_and_change_bit(int nr, volatile void * p);
-
-#define set_bit(n,p)              _set_bit(n,p)
-#define clear_bit(n,p)            _clear_bit(n,p)
-#define change_bit(n,p)           _change_bit(n,p)
-#define test_and_set_bit(n,p)     _test_and_set_bit(n,p)
-#define test_and_clear_bit(n,p)   _test_and_clear_bit(n,p)
-#define test_and_change_bit(n,p)  _test_and_change_bit(n,p)
+extern void set_bit(int nr, volatile void * p);
+extern void clear_bit(int nr, volatile void * p);
+extern void change_bit(int nr, volatile void * p);
+extern int test_and_set_bit(int nr, volatile void * p);
+extern int test_and_clear_bit(int nr, volatile void * p);
+extern int test_and_change_bit(int nr, volatile void * p);
 
 #define flsl fls
 
-- 
2.11.0
xsa295/unstable-05.patch (application/octet-stream, 2.7 KB)
From 07e336819827003e426a03e4b6a489dea593e2c7 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:20 +0100
Subject: [PATCH 05/15] xen/arm: bitops: Consolidate prototypes in one place

The prototype are the same between arm32 and arm64. Consolidate them in
asm-arm/bitops.h.

This change will help the introductions of new helpers in a follow-up
patch.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm32/bitops.h |  7 -------
 xen/include/asm-arm/arm64/bitops.h | 10 ----------
 xen/include/asm-arm/bitops.h       |  8 ++++++++
 3 files changed, 8 insertions(+), 17 deletions(-)

diff --git a/xen/include/asm-arm/arm32/bitops.h b/xen/include/asm-arm/arm32/bitops.h
index 67c4c3f55c..57938a5874 100644
--- a/xen/include/asm-arm/arm32/bitops.h
+++ b/xen/include/asm-arm/arm32/bitops.h
@@ -1,13 +1,6 @@
 #ifndef _ARM_ARM32_BITOPS_H
 #define _ARM_ARM32_BITOPS_H
 
-extern void set_bit(int nr, volatile void * p);
-extern void clear_bit(int nr, volatile void * p);
-extern void change_bit(int nr, volatile void * p);
-extern int test_and_set_bit(int nr, volatile void * p);
-extern int test_and_clear_bit(int nr, volatile void * p);
-extern int test_and_change_bit(int nr, volatile void * p);
-
 #define flsl fls
 
 /*
diff --git a/xen/include/asm-arm/arm64/bitops.h b/xen/include/asm-arm/arm64/bitops.h
index 6bf1922680..6cc224ad13 100644
--- a/xen/include/asm-arm/arm64/bitops.h
+++ b/xen/include/asm-arm/arm64/bitops.h
@@ -1,16 +1,6 @@
 #ifndef _ARM_ARM64_BITOPS_H
 #define _ARM_ARM64_BITOPS_H
 
-/*
- * Little endian assembly atomic bitops.
- */
-extern void set_bit(int nr, volatile void *p);
-extern void clear_bit(int nr, volatile void *p);
-extern void change_bit(int nr, volatile void *p);
-extern int test_and_set_bit(int nr, volatile void *p);
-extern int test_and_clear_bit(int nr, volatile void *p);
-extern int test_and_change_bit(int nr, volatile void *p);
-
 /* Based on linux/include/asm-generic/bitops/builtin-__ffs.h */
 /**
  * __ffs - find first bit in word.
diff --git a/xen/include/asm-arm/bitops.h b/xen/include/asm-arm/bitops.h
index 888584eaee..64899a36ab 100644
--- a/xen/include/asm-arm/bitops.h
+++ b/xen/include/asm-arm/bitops.h
@@ -36,6 +36,14 @@
 # error "unknown ARM variant"
 #endif
 
+/* Atomics bitops */
+void set_bit(int nr, volatile void *p);
+void clear_bit(int nr, volatile void *p);
+void change_bit(int nr, volatile void *p);
+int test_and_set_bit(int nr, volatile void *p);
+int test_and_clear_bit(int nr, volatile void *p);
+int test_and_change_bit(int nr, volatile void *p);
+
 /**
  * __test_and_set_bit - Set a bit and return its old value
  * @nr: Bit to set
-- 
2.11.0
xsa295/unstable-06.patch (application/octet-stream, 3.7 KB)
From 3f9184bf8a37cf62f7874c6f292bdb2d04b602a5 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Wed, 22 May 2019 13:37:53 -0700
Subject: [PATCH 06/15] xen/arm64: cmpxchg: Simplify the cmpxchg implementation

The only difference between each case of the cmpxchg is the size of
used. Rather than duplicating the code, provide a macro to generate each
cases.

This makes the code easier to read and modify.

This is part of XSA-295.

Signed-off-by; Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
Signed-off-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm64/cmpxchg.h | 98 ++++++++++++++-----------------------
 1 file changed, 36 insertions(+), 62 deletions(-)

diff --git a/xen/include/asm-arm/arm64/cmpxchg.h b/xen/include/asm-arm/arm64/cmpxchg.h
index 359271173e..f0f994dbc6 100644
--- a/xen/include/asm-arm/arm64/cmpxchg.h
+++ b/xen/include/asm-arm/arm64/cmpxchg.h
@@ -61,81 +61,55 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
 	__ret; \
 })
 
-extern void __bad_cmpxchg(volatile void *ptr, int size);
+extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
+
+#define __CMPXCHG_CASE(w, sz, name)					\
+static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
+						  unsigned long old,	\
+						  unsigned long new)	\
+{									\
+	unsigned long res, oldval;					\
+									\
+	do {								\
+		asm volatile("// __cmpxchg_case_" #name "\n"		\
+		"	ldxr" #sz "	%" #w "1, %2\n"			\
+		"	mov	%w0, #0\n"				\
+		"	cmp	%" #w "1, %" #w "3\n"			\
+		"	b.ne	1f\n"					\
+		"	stxr" #sz "	%w0, %" #w "4, %2\n"		\
+		"1:\n"							\
+		: "=&r" (res), "=&r" (oldval),				\
+		  "+Q" (*(unsigned long *)ptr)				\
+		: "Ir" (old), "r" (new)					\
+		: "cc");						\
+	} while (res);							\
+									\
+	return oldval;							\
+}
+
+__CMPXCHG_CASE(w, b, 1)
+__CMPXCHG_CASE(w, h, 2)
+__CMPXCHG_CASE(w,  , 4)
+__CMPXCHG_CASE( ,  , 8)
 
 static always_inline unsigned long __cmpxchg(volatile void *ptr,
 					     unsigned long old,
 					     unsigned long new, int size)
 {
-	unsigned long oldval = 0, res;
-
 	switch (size) {
 	case 1:
-		do {
-			asm volatile("// __cmpxchg1\n"
-			"	ldxrb	%w1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%w1, %w3\n"
-			"	b.ne	1f\n"
-			"	stxrb	%w0, %w4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u8 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_1(ptr, old, new);
 	case 2:
-		do {
-			asm volatile("// __cmpxchg2\n"
-			"	ldxrh	%w1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%w1, %w3\n"
-			"	b.ne	1f\n"
-			"	stxrh	%w0, %w4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u16 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_2(ptr, old, new);
 	case 4:
-		do {
-			asm volatile("// __cmpxchg4\n"
-			"	ldxr	%w1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%w1, %w3\n"
-			"	b.ne	1f\n"
-			"	stxr	%w0, %w4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u32 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_4(ptr, old, new);
 	case 8:
-		do {
-			asm volatile("// __cmpxchg8\n"
-			"	ldxr	%1, %2\n"
-			"	mov	%w0, #0\n"
-			"	cmp	%1, %3\n"
-			"	b.ne	1f\n"
-			"	stxr	%w0, %4, %2\n"
-			"1:\n"
-				: "=&r" (res), "=&r" (oldval), "+Q" (*(u64 *)ptr)
-				: "Ir" (old), "r" (new)
-				: "cc");
-		} while (res);
-		break;
-
+		return __cmpxchg_case_8(ptr, old, new);
 	default:
-		__bad_cmpxchg(ptr, size);
-		oldval = 0;
+		return __bad_cmpxchg(ptr, size);
 	}
 
-	return oldval;
+	ASSERT_UNREACHABLE();
 }
 
 static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
-- 
2.11.0
xsa295/unstable-07.patch (application/octet-stream, 3.6 KB)
From 07ecdc592b8435b8f2fa6e3d20faa2b147a1ea9f Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:22 +0100
Subject: [PATCH 07/15] xen/arm32: cmpxchg: Simplify the cmpxchg implementation

The only difference between each case of the cmpxchg is the size of
used. Rather than duplicating the code, provide a macro to generate each
cases.

This makes the code easier to read and modify.

While doing the rework, the case for 64-bit cmpxchg is removed. This is
unused today (already commented) and it would not be possible to use
it directly.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/include/asm-arm/arm32/cmpxchg.h | 84 ++++++++++++++-----------------------
 1 file changed, 31 insertions(+), 53 deletions(-)

diff --git a/xen/include/asm-arm/arm32/cmpxchg.h b/xen/include/asm-arm/arm32/cmpxchg.h
index 03e0bed3a6..471a9e3a3f 100644
--- a/xen/include/asm-arm/arm32/cmpxchg.h
+++ b/xen/include/asm-arm/arm32/cmpxchg.h
@@ -52,72 +52,50 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
  * indicated by comparing RETURN with OLD.
  */
 
-extern void __bad_cmpxchg(volatile void *ptr, int size);
+extern unsigned long __bad_cmpxchg(volatile void *ptr, int size);
+
+#define __CMPXCHG_CASE(sz, name)					\
+static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,	\
+						  unsigned long old,	\
+						  unsigned long new)	\
+{									\
+	unsigned long oldval, res;					\
+									\
+	do {								\
+		asm volatile("@ __cmpxchg_case_" #name "\n"		\
+		"	ldrex" #sz "	%1, [%2]\n"			\
+		"	mov	%0, #0\n"				\
+		"	teq	%1, %3\n"				\
+		"	strex" #sz "eq %0, %4, [%2]\n"			\
+		: "=&r" (res), "=&r" (oldval)				\
+		: "r" (ptr), "Ir" (old), "r" (new)			\
+		: "memory", "cc");					\
+	} while (res);							\
+									\
+	return oldval;							\
+}
+
+__CMPXCHG_CASE(b, 1)
+__CMPXCHG_CASE(h, 2)
+__CMPXCHG_CASE( , 4)
 
 static always_inline unsigned long __cmpxchg(
     volatile void *ptr, unsigned long old, unsigned long new, int size)
 {
-	unsigned long oldval, res;
-
 	prefetchw((const void *)ptr);
 
 	switch (size) {
 	case 1:
-		do {
-			asm volatile("@ __cmpxchg1\n"
-			"	ldrexb	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexbeq %0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-		} while (res);
-		break;
+		return __cmpxchg_case_1(ptr, old, new);
 	case 2:
-		do {
-			asm volatile("@ __cmpxchg2\n"
-			"	ldrexh	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexheq %0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-		} while (res);
-		break;
+		return __cmpxchg_case_2(ptr, old, new);
 	case 4:
-		do {
-			asm volatile("@ __cmpxchg4\n"
-			"	ldrex	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexeq	%0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-	    } while (res);
-	    break;
-#if 0
-	case 8:
-		do {
-			asm volatile("@ __cmpxchg8\n"
-			"	ldrexd	%1, [%2]\n"
-			"	mov	%0, #0\n"
-			"	teq	%1, %3\n"
-			"	strexdeq %0, %4, [%2]\n"
-				: "=&r" (res), "=&r" (oldval)
-				: "r" (ptr), "Ir" (old), "r" (new)
-				: "memory", "cc");
-		} while (res);
-		break;
-#endif
+		return __cmpxchg_case_4(ptr, old, new);
 	default:
-		__bad_cmpxchg(ptr, size);
-		oldval = 0;
+		return __bad_cmpxchg(ptr, size);
 	}
 
-	return oldval;
+	ASSERT_UNREACHABLE();
 }
 
 static always_inline unsigned long __cmpxchg_mb(volatile void *ptr,
-- 
2.11.0
xsa295/unstable-08.patch (application/octet-stream, 12.7 KB)
From aa010dfe33848272d08dc1ccbcc759e599fa3640 Mon Sep 17 00:00:00 2001
From: Julien Grall <[email protected]>
Date: Mon, 29 Apr 2019 15:05:23 +0100
Subject: [PATCH 08/15] xen/arm: bitops: Implement a new set of helpers that
 can timeout

Exclusive load-store atomics should only be used between trusted
threads. As not all the guests are trusted, it may be possible to DoS
Xen when updating shared memory with guest atomically.

To prevent the infinite loop, we introduce a new set of helpers that can
timeout. The timeout is based on the maximum number of iterations.

They will be used in follow-up patch to make atomic operations
on shared memory safe.

This is part of XSA-295.

Signed-off-by: Julien Grall <[email protected]>
Reviewed-by: Stefano Stabellini <[email protected]>
---
 xen/arch/arm/arm32/lib/bitops.c | 52 +++++++++++++++++++++++++++++++++++------
 xen/arch/arm/arm64/lib/bitops.c | 52 +++++++++++++++++++++++++++++++++++------
 xen/include/asm-arm/bitops.h    | 28 +++++++++++++++++++++-
 3 files changed, 117 insertions(+), 15 deletions(-)

diff --git a/xen/arch/arm/arm32/lib/bitops.c b/xen/arch/arm/arm32/lib/bitops.c
index c69bb53037..08750314fc 100644
--- a/xen/arch/arm/arm32/lib/bitops.c
+++ b/xen/arch/arm/arm32/lib/bitops.c
@@ -30,7 +30,8 @@
  */
 
 #define bitop(name, instr)                                                  \
-void name(int nr, volatile void *p)                                         \
+static always_inline bool int_##name(int nr, volatile void *p, bool timeout,\
+                                     unsigned int max_try)                  \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
@@ -47,17 +48,33 @@ void name(int nr, volatile void *p)                                         \
         "   strex   %0, %2, %1\n"                                           \
         : "=&r" (res), "+Qo" (*ptr), "=&r" (tmp)                            \
         : "r" (mask));                                                      \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
+                                                                            \
+    return !res;                                                            \
+}                                                                           \
+                                                                            \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    if ( !int_##name(nr, p, false, 0) )                                     \
+        ASSERT_UNREACHABLE();                                               \
+}                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p, unsigned int max_try)         \
+{                                                                           \
+    return int_##name(nr, p, true, max_try);                                \
 }
 
 #define testop(name, instr)                                                 \
-int name(int nr, volatile void *p)                                          \
+static always_inline bool int_##name(int nr, volatile void *p, int *oldbit, \
+                                     bool timeout, unsigned int max_try)    \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
     const uint32_t mask = BIT_MASK(bit);                                    \
     unsigned long res, tmp;                                                 \
-    int oldbit;                                                             \
                                                                             \
     ASSERT(((vaddr_t)p & 0x3) == 0);                                        \
     smp_mb();                                                               \
@@ -71,14 +88,35 @@ int name(int nr, volatile void *p)                                          \
         "   lsr     %1, %3, %5 // Save old value of bit\n"                  \
         "   " __stringify(instr) "  %3, %3, %4 // Toggle bit\n"             \
         "   strex  %0, %3, %2\n"                                            \
-        : "=&r" (res), "=&r" (oldbit), "+Qo" (*ptr), "=&r" (tmp)            \
+        : "=&r" (res), "=&r" (*oldbit), "+Qo" (*ptr), "=&r" (tmp)           \
         : "r" (mask), "r" (bit));                                           \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
                                                                             \
     smp_mb();                                                               \
                                                                             \
-    return oldbit & 1;                                                      \
+    *oldbit &= 1;                                                           \
+                                                                            \
+    return !res;                                                            \
+}                                                                           \
+                                                                            \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    int oldbit;                                                             \
+                                                                            \
+    if ( !int_##name(nr, p, &oldbit, false, 0) )                            \
+        ASSERT_UNREACHABLE();                                               \
+                                                                            \
+    return oldbit;                                                          \
 }                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p,                               \
+                    int *oldbit, unsigned int max_try)                      \
+{                                                                           \
+    return int_##name(nr, p, oldbit, true, max_try);                        \
+}
 
 bitop(change_bit, eor)
 bitop(clear_bit, bic)
diff --git a/xen/arch/arm/arm64/lib/bitops.c b/xen/arch/arm/arm64/lib/bitops.c
index b1c681c642..78bf4ed8c5 100644
--- a/xen/arch/arm/arm64/lib/bitops.c
+++ b/xen/arch/arm/arm64/lib/bitops.c
@@ -29,7 +29,8 @@
  */
 
 #define bitop(name, instr)                                                  \
-void name(int nr, volatile void *p)                                         \
+static always_inline bool int_##name(int nr, volatile void *p, bool timeout,\
+                                     unsigned int max_try)                  \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     const uint32_t mask = BIT_MASK((unsigned int)nr);                       \
@@ -43,17 +44,33 @@ void name(int nr, volatile void *p)                                         \
         "   stxr    %w0, %w2, %1\n"                                         \
         : "=&r" (res), "+Q" (*ptr), "=&r" (tmp)                             \
         : "r" (mask));                                                      \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
+                                                                            \
+    return !res;                                                            \
 }                                                                           \
+                                                                            \
+void name(int nr, volatile void *p)                                         \
+{                                                                           \
+    if ( !int_##name(nr, p, false, 0) )                                     \
+        ASSERT_UNREACHABLE();                                               \
+}                                                                           \
+                                                                            \
+bool name##_timeout(int nr, volatile void *p, unsigned int max_try)         \
+{                                                                           \
+    return int_##name(nr, p, true, max_try);                                \
+}
 
 #define testop(name, instr)                                                 \
-int name(int nr, volatile void *p)                                          \
+static always_inline bool int_##name(int nr, volatile void *p, int *oldbit, \
+                                     bool timeout, unsigned int max_try)    \
 {                                                                           \
     volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr);    \
     unsigned int bit = (unsigned int)nr % BITS_PER_WORD;                    \
     const uint32_t mask = BIT_MASK(bit);                                    \
     unsigned long res, tmp;                                                 \
-    unsigned long oldbit;                                                   \
                                                                             \
     do                                                                      \
     {                                                                       \
@@ -62,14 +79,35 @@ int name(int nr, volatile void *p)                                          \
         "   lsr     %w1, %w3, %w5 // Save old value of bit\n"               \
         "   " __stringify(instr) "  %w3, %w3, %w4 // Toggle bit\n"          \
         "   stlxr   %w0, %w3, %2\n"                                         \
-        : "=&r" (res), "=&r" (oldbit), "+Q" (*ptr), "=&r" (tmp)             \
+        : "=&r" (res), "=&r" (*oldbit), "+Q" (*ptr), "=&r" (tmp)            \
         : "r" (mask), "r" (bit)                                             \
         : "memory");                                                        \
-    } while ( res );                                                        \
+                                                                            \
+        if ( !res )                                                         \
+            break;                                                          \
+    } while ( !timeout || ((--max_try) > 0) );                              \
                                                                             \
     dmb(ish);                                                               \
                                                                             \
-    return oldbit & 1;                                                      \
+    *oldbit &= 1;                                                           \
+                                                                            \
+    return !res;                                                            \
+}                                                                           \
+                                                                            \
+int name(int nr, volatile void *p)                                          \
+{                                                                           \
+    int oldbit;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.