Merge e109f50607
("Merge tag 'mtd/for-5.7' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux") into android-mainline
Baby steps on the way to 5.7-rc1 Change-Id: I136ebb5242e3499873dcd5f5178ad7f68512d11c Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
commit
47627513ce
@ -2,13 +2,6 @@
|
||||
HugeTLB Controller
|
||||
==================
|
||||
|
||||
The HugeTLB controller allows to limit the HugeTLB usage per control group and
|
||||
enforces the controller limit during page fault. Since HugeTLB doesn't
|
||||
support page reclaim, enforcing the limit at page fault time implies that,
|
||||
the application will get SIGBUS signal if it tries to access HugeTLB pages
|
||||
beyond its limit. This requires the application to know beforehand how much
|
||||
HugeTLB pages it would require for its use.
|
||||
|
||||
HugeTLB controller can be created by first mounting the cgroup filesystem.
|
||||
|
||||
# mount -t cgroup -o hugetlb none /sys/fs/cgroup
|
||||
@ -28,10 +21,14 @@ process (bash) into it.
|
||||
|
||||
Brief summary of control files::
|
||||
|
||||
hugetlb.<hugepagesize>.limit_in_bytes # set/show limit of "hugepagesize" hugetlb usage
|
||||
hugetlb.<hugepagesize>.max_usage_in_bytes # show max "hugepagesize" hugetlb usage recorded
|
||||
hugetlb.<hugepagesize>.usage_in_bytes # show current usage for "hugepagesize" hugetlb
|
||||
hugetlb.<hugepagesize>.failcnt # show the number of allocation failure due to HugeTLB limit
|
||||
hugetlb.<hugepagesize>.rsvd.limit_in_bytes # set/show limit of "hugepagesize" hugetlb reservations
|
||||
hugetlb.<hugepagesize>.rsvd.max_usage_in_bytes # show max "hugepagesize" hugetlb reservations and no-reserve faults
|
||||
hugetlb.<hugepagesize>.rsvd.usage_in_bytes # show current reservations and no-reserve faults for "hugepagesize" hugetlb
|
||||
hugetlb.<hugepagesize>.rsvd.failcnt # show the number of allocation failure due to HugeTLB reservation limit
|
||||
hugetlb.<hugepagesize>.limit_in_bytes # set/show limit of "hugepagesize" hugetlb faults
|
||||
hugetlb.<hugepagesize>.max_usage_in_bytes # show max "hugepagesize" hugetlb usage recorded
|
||||
hugetlb.<hugepagesize>.usage_in_bytes # show current usage for "hugepagesize" hugetlb
|
||||
hugetlb.<hugepagesize>.failcnt # show the number of allocation failure due to HugeTLB usage limit
|
||||
|
||||
For a system supporting three hugepage sizes (64k, 32M and 1G), the control
|
||||
files include::
|
||||
@ -40,11 +37,95 @@ files include::
|
||||
hugetlb.1GB.max_usage_in_bytes
|
||||
hugetlb.1GB.usage_in_bytes
|
||||
hugetlb.1GB.failcnt
|
||||
hugetlb.1GB.rsvd.limit_in_bytes
|
||||
hugetlb.1GB.rsvd.max_usage_in_bytes
|
||||
hugetlb.1GB.rsvd.usage_in_bytes
|
||||
hugetlb.1GB.rsvd.failcnt
|
||||
hugetlb.64KB.limit_in_bytes
|
||||
hugetlb.64KB.max_usage_in_bytes
|
||||
hugetlb.64KB.usage_in_bytes
|
||||
hugetlb.64KB.failcnt
|
||||
hugetlb.64KB.rsvd.limit_in_bytes
|
||||
hugetlb.64KB.rsvd.max_usage_in_bytes
|
||||
hugetlb.64KB.rsvd.usage_in_bytes
|
||||
hugetlb.64KB.rsvd.failcnt
|
||||
hugetlb.32MB.limit_in_bytes
|
||||
hugetlb.32MB.max_usage_in_bytes
|
||||
hugetlb.32MB.usage_in_bytes
|
||||
hugetlb.32MB.failcnt
|
||||
hugetlb.32MB.rsvd.limit_in_bytes
|
||||
hugetlb.32MB.rsvd.max_usage_in_bytes
|
||||
hugetlb.32MB.rsvd.usage_in_bytes
|
||||
hugetlb.32MB.rsvd.failcnt
|
||||
|
||||
|
||||
1. Page fault accounting
|
||||
|
||||
hugetlb.<hugepagesize>.limit_in_bytes
|
||||
hugetlb.<hugepagesize>.max_usage_in_bytes
|
||||
hugetlb.<hugepagesize>.usage_in_bytes
|
||||
hugetlb.<hugepagesize>.failcnt
|
||||
|
||||
The HugeTLB controller allows users to limit the HugeTLB usage (page fault) per
|
||||
control group and enforces the limit during page fault. Since HugeTLB
|
||||
doesn't support page reclaim, enforcing the limit at page fault time implies
|
||||
that, the application will get SIGBUS signal if it tries to fault in HugeTLB
|
||||
pages beyond its limit. Therefore the application needs to know exactly how many
|
||||
HugeTLB pages it uses before hand, and the sysadmin needs to make sure that
|
||||
there are enough available on the machine for all the users to avoid processes
|
||||
getting SIGBUS.
|
||||
|
||||
|
||||
2. Reservation accounting
|
||||
|
||||
hugetlb.<hugepagesize>.rsvd.limit_in_bytes
|
||||
hugetlb.<hugepagesize>.rsvd.max_usage_in_bytes
|
||||
hugetlb.<hugepagesize>.rsvd.usage_in_bytes
|
||||
hugetlb.<hugepagesize>.rsvd.failcnt
|
||||
|
||||
The HugeTLB controller allows to limit the HugeTLB reservations per control
|
||||
group and enforces the controller limit at reservation time and at the fault of
|
||||
HugeTLB memory for which no reservation exists. Since reservation limits are
|
||||
enforced at reservation time (on mmap or shget), reservation limits never causes
|
||||
the application to get SIGBUS signal if the memory was reserved before hand. For
|
||||
MAP_NORESERVE allocations, the reservation limit behaves the same as the fault
|
||||
limit, enforcing memory usage at fault time and causing the application to
|
||||
receive a SIGBUS if it's crossing its limit.
|
||||
|
||||
Reservation limits are superior to page fault limits described above, since
|
||||
reservation limits are enforced at reservation time (on mmap or shget), and
|
||||
never causes the application to get SIGBUS signal if the memory was reserved
|
||||
before hand. This allows for easier fallback to alternatives such as
|
||||
non-HugeTLB memory for example. In the case of page fault accounting, it's very
|
||||
hard to avoid processes getting SIGBUS since the sysadmin needs precisely know
|
||||
the HugeTLB usage of all the tasks in the system and make sure there is enough
|
||||
pages to satisfy all requests. Avoiding tasks getting SIGBUS on overcommited
|
||||
systems is practically impossible with page fault accounting.
|
||||
|
||||
|
||||
3. Caveats with shared memory
|
||||
|
||||
For shared HugeTLB memory, both HugeTLB reservation and page faults are charged
|
||||
to the first task that causes the memory to be reserved or faulted, and all
|
||||
subsequent uses of this reserved or faulted memory is done without charging.
|
||||
|
||||
Shared HugeTLB memory is only uncharged when it is unreserved or deallocated.
|
||||
This is usually when the HugeTLB file is deleted, and not when the task that
|
||||
caused the reservation or fault has exited.
|
||||
|
||||
|
||||
4. Caveats with HugeTLB cgroup offline.
|
||||
|
||||
When a HugeTLB cgroup goes offline with some reservations or faults still
|
||||
charged to it, the behavior is as follows:
|
||||
|
||||
- The fault charges are charged to the parent HugeTLB cgroup (reparented),
|
||||
- the reservation charges remain on the offline HugeTLB cgroup.
|
||||
|
||||
This means that if a HugeTLB cgroup gets offlined while there is still HugeTLB
|
||||
reservations charged to it, that cgroup persists as a zombie until all HugeTLB
|
||||
reservations are uncharged. HugeTLB reservations behave in this manner to match
|
||||
the memory controller whose cgroups also persist as zombie until all charged
|
||||
memory is uncharged. Also, the tracking of HugeTLB reservations is a bit more
|
||||
complex compared to the tracking of HugeTLB faults, so it is significantly
|
||||
harder to reparent reservations at offline time.
|
||||
|
@ -188,6 +188,17 @@ cgroup v2 currently supports the following mount options.
|
||||
modified through remount from the init namespace. The mount
|
||||
option is ignored on non-init namespace mounts.
|
||||
|
||||
memory_recursiveprot
|
||||
|
||||
Recursively apply memory.min and memory.low protection to
|
||||
entire subtrees, without requiring explicit downward
|
||||
propagation into leaf cgroups. This allows protecting entire
|
||||
subtrees from one another, while retaining free competition
|
||||
within those subtrees. This should have been the default
|
||||
behavior but is a mount-option to avoid regressing setups
|
||||
relying on the original semantics (e.g. specifying bogusly
|
||||
high 'bypass' protection values at higher tree levels).
|
||||
|
||||
|
||||
Organizing Processes and Threads
|
||||
--------------------------------
|
||||
|
@ -3821,6 +3821,11 @@
|
||||
before loading.
|
||||
See Documentation/admin-guide/blockdev/ramdisk.rst.
|
||||
|
||||
prot_virt= [S390] enable hosting protected virtual machines
|
||||
isolated from the hypervisor (if hardware supports
|
||||
that).
|
||||
Format: <bool>
|
||||
|
||||
psi= [KNL] Enable or disable pressure stall information
|
||||
tracking.
|
||||
Format: <bool>
|
||||
|
@ -129,6 +129,9 @@ allowed to examine the unevictable lru (mlocked pages) for pages to compact.
|
||||
This should be used on systems where stalls for minor page faults are an
|
||||
acceptable trade for large contiguous free memory. Set to 0 to prevent
|
||||
compaction from moving pages that are unevictable. Default value is 1.
|
||||
On CONFIG_PREEMPT_RT the default value is 0 in order to avoid a page fault, due
|
||||
to compaction, which would block the task from becomming active until the fault
|
||||
is resolved.
|
||||
|
||||
|
||||
dirty_background_bytes
|
||||
|
@ -73,6 +73,9 @@ File Mapping and Page Cache
|
||||
.. kernel-doc:: mm/truncate.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/linux/pagemap.h
|
||||
:internal:
|
||||
|
||||
Memory pools
|
||||
============
|
||||
|
||||
|
@ -52,8 +52,22 @@ Which flags are set by each wrapper
|
||||
|
||||
For these pin_user_pages*() functions, FOLL_PIN is OR'd in with whatever gup
|
||||
flags the caller provides. The caller is required to pass in a non-null struct
|
||||
pages* array, and the function then pin pages by incrementing each by a special
|
||||
value. For now, that value is +1, just like get_user_pages*().::
|
||||
pages* array, and the function then pins pages by incrementing each by a special
|
||||
value: GUP_PIN_COUNTING_BIAS.
|
||||
|
||||
For huge pages (and in fact, any compound page of more than 2 pages), the
|
||||
GUP_PIN_COUNTING_BIAS scheme is not used. Instead, an exact form of pin counting
|
||||
is achieved, by using the 3rd struct page in the compound page. A new struct
|
||||
page field, hpage_pinned_refcount, has been added in order to support this.
|
||||
|
||||
This approach for compound pages avoids the counting upper limit problems that
|
||||
are discussed below. Those limitations would have been aggravated severely by
|
||||
huge pages, because each tail page adds a refcount to the head page. And in
|
||||
fact, testing revealed that, without a separate hpage_pinned_refcount field,
|
||||
page overflows were seen in some huge page stress tests.
|
||||
|
||||
This also means that huge pages and compound pages (of order > 1) do not suffer
|
||||
from the false positives problem that is mentioned below.::
|
||||
|
||||
Function
|
||||
--------
|
||||
@ -99,27 +113,6 @@ pages:
|
||||
This also leads to limitations: there are only 31-10==21 bits available for a
|
||||
counter that increments 10 bits at a time.
|
||||
|
||||
TODO: for 1GB and larger huge pages, this is cutting it close. That's because
|
||||
when pin_user_pages() follows such pages, it increments the head page by "1"
|
||||
(where "1" used to mean "+1" for get_user_pages(), but now means "+1024" for
|
||||
pin_user_pages()) for each tail page. So if you have a 1GB huge page:
|
||||
|
||||
* There are 256K (18 bits) worth of 4 KB tail pages.
|
||||
* There are 21 bits available to count up via GUP_PIN_COUNTING_BIAS (that is,
|
||||
10 bits at a time)
|
||||
* There are 21 - 18 == 3 bits available to count. Except that there aren't,
|
||||
because you need to allow for a few normal get_page() calls on the head page,
|
||||
as well. Fortunately, the approach of using addition, rather than "hard"
|
||||
bitfields, within page->_refcount, allows for sharing these bits gracefully.
|
||||
But we're still looking at about 8 references.
|
||||
|
||||
This, however, is a missing feature more than anything else, because it's easily
|
||||
solved by addressing an obvious inefficiency in the original get_user_pages()
|
||||
approach of retrieving pages: stop treating all the pages as if they were
|
||||
PAGE_SIZE. Retrieve huge pages as huge pages. The callers need to be aware of
|
||||
this, so some work is required. Once that's in place, this limitation mostly
|
||||
disappears from view, because there will be ample refcounting range available.
|
||||
|
||||
* Callers must specifically request "dma-pinned tracking of pages". In other
|
||||
words, just calling get_user_pages() will not suffice; a new set of functions,
|
||||
pin_user_page() and related, must be used.
|
||||
@ -173,8 +166,8 @@ CASE 4: Pinning for struct page manipulation only
|
||||
-------------------------------------------------
|
||||
Here, normal GUP calls are sufficient, so neither flag needs to be set.
|
||||
|
||||
page_dma_pinned(): the whole point of pinning
|
||||
=============================================
|
||||
page_maybe_dma_pinned(): the whole point of pinning
|
||||
===================================================
|
||||
|
||||
The whole point of marking pages as "DMA-pinned" or "gup-pinned" is to be able
|
||||
to query, "is this page DMA-pinned?" That allows code such as page_mkclean()
|
||||
@ -186,7 +179,7 @@ and debates (see the References at the end of this document). It's a TODO item
|
||||
here: fill in the details once that's worked out. Meanwhile, it's safe to say
|
||||
that having this available: ::
|
||||
|
||||
static inline bool page_dma_pinned(struct page *page)
|
||||
static inline bool page_maybe_dma_pinned(struct page *page)
|
||||
|
||||
...is a prerequisite to solving the long-running gup+DMA problem.
|
||||
|
||||
@ -215,12 +208,42 @@ has the following new calls to exercise the new pin*() wrapper functions:
|
||||
You can monitor how many total dma-pinned pages have been acquired and released
|
||||
since the system was booted, via two new /proc/vmstat entries: ::
|
||||
|
||||
/proc/vmstat/nr_foll_pin_requested
|
||||
/proc/vmstat/nr_foll_pin_requested
|
||||
/proc/vmstat/nr_foll_pin_acquired
|
||||
/proc/vmstat/nr_foll_pin_released
|
||||
|
||||
Those are both going to show zero, unless CONFIG_DEBUG_VM is set. This is
|
||||
because there is a noticeable performance drop in unpin_user_page(), when they
|
||||
are activated.
|
||||
Under normal conditions, these two values will be equal unless there are any
|
||||
long-term [R]DMA pins in place, or during pin/unpin transitions.
|
||||
|
||||
* nr_foll_pin_acquired: This is the number of logical pins that have been
|
||||
acquired since the system was powered on. For huge pages, the head page is
|
||||
pinned once for each page (head page and each tail page) within the huge page.
|
||||
This follows the same sort of behavior that get_user_pages() uses for huge
|
||||
pages: the head page is refcounted once for each tail or head page in the huge
|
||||
page, when get_user_pages() is applied to a huge page.
|
||||
|
||||
* nr_foll_pin_released: The number of logical pins that have been released since
|
||||
the system was powered on. Note that pages are released (unpinned) on a
|
||||
PAGE_SIZE granularity, even if the original pin was applied to a huge page.
|
||||
Becaused of the pin count behavior described above in "nr_foll_pin_acquired",
|
||||
the accounting balances out, so that after doing this::
|
||||
|
||||
pin_user_pages(huge_page);
|
||||
for (each page in huge_page)
|
||||
unpin_user_page(page);
|
||||
|
||||
...the following is expected::
|
||||
|
||||
nr_foll_pin_released == nr_foll_pin_acquired
|
||||
|
||||
(...unless it was already out of balance due to a long-term RDMA pin being in
|
||||
place.)
|
||||
|
||||
Other diagnostics
|
||||
=================
|
||||
|
||||
dump_page() has been enhanced slightly, to handle these new counting fields, and
|
||||
to better report on compound pages in general. Specifically, for compound pages
|
||||
with order > 1, the exact (hpage_pinned_refcount) pincount is reported.
|
||||
|
||||
References
|
||||
==========
|
||||
@ -228,5 +251,6 @@ References
|
||||
* `Some slow progress on get_user_pages() (Apr 2, 2019) <https://lwn.net/Articles/784574/>`_
|
||||
* `DMA and get_user_pages() (LPC: Dec 12, 2018) <https://lwn.net/Articles/774411/>`_
|
||||
* `The trouble with get_user_pages() (Apr 30, 2018) <https://lwn.net/Articles/753027/>`_
|
||||
* `LWN kernel index: get_user_pages() <https://lwn.net/Kernel/Index/#Memory_management-get_user_pages>`_
|
||||
|
||||
John Hubbard, October, 2019
|
||||
|
@ -16,6 +16,7 @@ Required Properties:
|
||||
- "renesas,r8a7794-usb-dmac" (R-Car E2)
|
||||
- "renesas,r8a7795-usb-dmac" (R-Car H3)
|
||||
- "renesas,r8a7796-usb-dmac" (R-Car M3-W)
|
||||
- "renesas,r8a77961-usb-dmac" (R-Car M3-W+)
|
||||
- "renesas,r8a77965-usb-dmac" (R-Car M3-N)
|
||||
- "renesas,r8a77990-usb-dmac" (R-Car E3)
|
||||
- "renesas,r8a77995-usb-dmac" (R-Car D3)
|
||||
|
@ -0,0 +1,63 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/dma/socionext,uniphier-xdmac.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Socionext UniPhier external DMA controller
|
||||
|
||||
description: |
|
||||
This describes the devicetree bindings for an external DMA engine to perform
|
||||
memory-to-memory or peripheral-to-memory data transfer capable of supporting
|
||||
16 channels, implemented in Socionext UniPhier SoCs.
|
||||
|
||||
maintainers:
|
||||
- Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "dma-controller.yaml#"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: socionext,uniphier-xdmac
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: XDMAC base register region (offset and length)
|
||||
- description: XDMAC extension register region (offset and length)
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
"#dma-cells":
|
||||
const: 2
|
||||
description: |
|
||||
DMA request from clients consists of 2 cells:
|
||||
1. Channel index
|
||||
2. Transfer request factor number, If no transfer factor, use 0.
|
||||
The number is SoC-specific, and this should be specified with
|
||||
relation to the device to use the DMA controller.
|
||||
|
||||
dma-channels:
|
||||
minimum: 1
|
||||
maximum: 16
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- "#dma-cells"
|
||||
|
||||
examples:
|
||||
- |
|
||||
xdmac: dma-controller@5fc10000 {
|
||||
compatible = "socionext,uniphier-xdmac";
|
||||
reg = <0x5fc10000 0x1000>, <0x5fc20000 0x800>;
|
||||
interrupts = <0 188 4>;
|
||||
#dma-cells = <2>;
|
||||
dma-channels = <16>;
|
||||
};
|
||||
|
||||
...
|
@ -180,7 +180,7 @@ edma1_tptc0: tptc@27b0000 {
|
||||
};
|
||||
|
||||
edma1_tptc1: tptc@27b8000 {
|
||||
compatible = "ti, k2g-edma3-tptc", "ti,edma3-tptc";
|
||||
compatible = "ti,k2g-edma3-tptc", "ti,edma3-tptc";
|
||||
reg = <0x027b8000 0x400>;
|
||||
power-domains = <&k2g_pds 0x4f>;
|
||||
};
|
||||
|
@ -45,7 +45,8 @@ allOf:
|
||||
|
||||
properties:
|
||||
"#dma-cells":
|
||||
const: 1
|
||||
minimum: 1
|
||||
maximum: 2
|
||||
description: |
|
||||
The cell is the PSI-L thread ID of the remote (to UDMAP) end.
|
||||
Valid ranges for thread ID depends on the data movement direction:
|
||||
@ -55,6 +56,8 @@ properties:
|
||||
Please refer to the device documentation for the PSI-L thread map and also
|
||||
the PSI-L peripheral chapter for the correct thread ID.
|
||||
|
||||
When #dma-cells is 2, the second parameter is the channel ATYPE.
|
||||
|
||||
compatible:
|
||||
enum:
|
||||
- ti,am654-navss-main-udmap
|
||||
@ -131,6 +134,20 @@ required:
|
||||
- ti,sci-rm-range-rchan
|
||||
- ti,sci-rm-range-rflow
|
||||
|
||||
if:
|
||||
properties:
|
||||
"#dma-cells":
|
||||
const: 2
|
||||
then:
|
||||
properties:
|
||||
ti,udma-atype:
|
||||
description: ATYPE value which should be used by non slave channels
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
required:
|
||||
- ti,udma-atype
|
||||
|
||||
examples:
|
||||
- |+
|
||||
cbass_main {
|
||||
|
97
Documentation/devicetree/bindings/i2c/brcm,brcmstb-i2c.yaml
Normal file
97
Documentation/devicetree/bindings/i2c/brcm,brcmstb-i2c.yaml
Normal file
@ -0,0 +1,97 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/i2c/brcm,brcmstb-i2c.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Broadcom STB BSC IIC Master Controller
|
||||
|
||||
maintainers:
|
||||
- Kamal Dasu <kdasu.kdev@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/i2c/i2c-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- brcm,bcm2711-hdmi-i2c
|
||||
- brcm,brcmstb-i2c
|
||||
- brcm,brcmper-i2c
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- description: BSC register range
|
||||
- description: Auto-I2C register range
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: bsc
|
||||
- const: auto-i2c
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
interrupt-names:
|
||||
maxItems: 1
|
||||
|
||||
clock-frequency:
|
||||
enum:
|
||||
- 46875
|
||||
- 50000
|
||||
- 93750
|
||||
- 97500
|
||||
- 187500
|
||||
- 200000
|
||||
- 375000
|
||||
- 390000
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clock-frequency
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- brcm,bcm2711-hdmi-i2c
|
||||
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 2
|
||||
|
||||
required:
|
||||
- reg-names
|
||||
|
||||
else:
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
examples:
|
||||
- |
|
||||
bsca: i2c@f0406200 {
|
||||
clock-frequency = <390000>;
|
||||
compatible = "brcm,brcmstb-i2c";
|
||||
interrupt-parent = <&irq0_intc>;
|
||||
reg = <0xf0406200 0x58>;
|
||||
interrupts = <0x18>;
|
||||
interrupt-names = "upg_bsca";
|
||||
};
|
||||
|
||||
- |
|
||||
ddc0: i2c@7ef04500 {
|
||||
compatible = "brcm,bcm2711-hdmi-i2c";
|
||||
reg = <0x7ef04500 0x100>, <0x7ef00b00 0x300>;
|
||||
reg-names = "bsc", "auto-i2c";
|
||||
clock-frequency = <390000>;
|
||||
};
|
||||
|
||||
...
|
@ -28,8 +28,13 @@ Optional properties:
|
||||
"atmel,sama5d4-i2c",
|
||||
"atmel,sama5d2-i2c",
|
||||
"microchip,sam9x60-i2c".
|
||||
- scl-gpios: specify the gpio related to SCL pin
|
||||
- sda-gpios: specify the gpio related to SDA pin
|
||||
- pinctrl: add extra pinctrl to configure i2c pins to gpio function for i2c
|
||||
bus recovery, call it "gpio" state
|
||||
- Child nodes conforming to i2c bus binding
|
||||
|
||||
|
||||
Examples :
|
||||
|
||||
i2c0: i2c@fff84000 {
|
||||
@ -64,6 +69,11 @@ i2c0: i2c@f8034600 {
|
||||
clocks = <&flx0>;
|
||||
atmel,fifo-size = <16>;
|
||||
i2c-sda-hold-time-ns = <336>;
|
||||
pinctrl-names = "default", "gpio";
|
||||
pinctrl-0 = <&pinctrl_i2c0>;
|
||||
pinctrl-1 = <&pinctrl_i2c0_gpio>;
|
||||
sda-gpios = <&pioA 30 GPIO_ACTIVE_HIGH>;
|
||||
scl-gpios = <&pioA 31 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
wm8731: wm8731@1a {
|
||||
compatible = "wm8731";
|
||||
|
@ -1,26 +0,0 @@
|
||||
Broadcom stb bsc iic master controller
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: should be "brcm,brcmstb-i2c" or "brcm,brcmper-i2c"
|
||||
- clock-frequency: 32-bit decimal value of iic master clock freqency in Hz
|
||||
valid values are 375000, 390000, 187500, 200000
|
||||
93750, 97500, 46875 and 50000
|
||||
- reg: specifies the base physical address and size of the registers
|
||||
|
||||
Optional properties :
|
||||
|
||||
- interrupts: specifies the interrupt number, the irq line to be used
|
||||
- interrupt-names: Interrupt name string
|
||||
|
||||
Example:
|
||||
|
||||
bsca: i2c@f0406200 {
|
||||
clock-frequency = <390000>;
|
||||
compatible = "brcm,brcmstb-i2c";
|
||||
interrupt-parent = <&irq0_intc>;
|
||||
reg = <0xf0406200 0x58>;
|
||||
interrupts = <0x18>;
|
||||
interrupt-names = "upg_bsca";
|
||||
};
|
||||
|
@ -35,11 +35,11 @@ Required properties:
|
||||
(optional) NAND flash cache range (if at non-standard offset)
|
||||
- reg-names : a list of the names corresponding to the previous register
|
||||
ranges. Should contain "nand" and (optionally)
|
||||
"flash-dma" and/or "nand-cache".
|
||||
- interrupts : The NAND CTLRDY interrupt and (if Flash DMA is available)
|
||||
FLASH_DMA_DONE
|
||||
- interrupt-names : May be "nand_ctlrdy" or "flash_dma_done", if broken out as
|
||||
individual interrupts.
|
||||
"flash-dma" or "flash-edu" and/or "nand-cache".
|
||||
- interrupts : The NAND CTLRDY interrupt, (if Flash DMA is available)
|
||||
FLASH_DMA_DONE and if EDU is avaialble and used FLASH_EDU_DONE
|
||||
- interrupt-names : May be "nand_ctlrdy" or "flash_dma_done" or "flash_edu_done",
|
||||
if broken out as individual interrupts.
|
||||
May be "nand", if the SoC has the individual NAND
|
||||
interrupts multiplexed behind another custom piece of
|
||||
hardware
|
||||
|
27
Documentation/devicetree/bindings/mtd/nand-macronix.txt
Normal file
27
Documentation/devicetree/bindings/mtd/nand-macronix.txt
Normal file
@ -0,0 +1,27 @@
|
||||
Macronix NANDs Device Tree Bindings
|
||||
-----------------------------------
|
||||
|
||||
Macronix NANDs support randomizer operation for scrambling user data,
|
||||
which can be enabled with a SET_FEATURE. The penalty when using the
|
||||
randomizer are subpage accesses prohibited and more time period needed
|
||||
for program operation, i.e., tPROG 300us to 340us (randomizer enabled).
|
||||
Enabling the randomizer is a one time persistent and non reversible
|
||||
operation.
|
||||
|
||||
For more high-reliability concern, if subpage write is not available
|
||||
with hardware ECC and not enabled at UBI level, then enabling the
|
||||
randomizer is recommended by default by adding a new specific property
|
||||
in children nodes.
|
||||
|
||||
Required NAND chip properties in children mode:
|
||||
- randomizer enable: should be "mxic,enable-randomizer-otp"
|
||||
|
||||
Example:
|
||||
|
||||
nand: nand-controller@unit-address {
|
||||
|
||||
nand@0 {
|
||||
reg = <0>;
|
||||
mxic,enable-randomizer-otp;
|
||||
};
|
||||
};
|
@ -38,7 +38,7 @@ Bank: 3 (A, B and C)
|
||||
0xffffffff 0x7fff3ccf /* pioB */
|
||||
0xffffffff 0x007fffff /* pioC */
|
||||
|
||||
For each peripheral/bank we will descibe in a u32 if a pin can be
|
||||
For each peripheral/bank we will describe in a u32 if a pin can be
|
||||
configured in it by putting 1 to the pin bit (1 << pin)
|
||||
|
||||
Let's take the pioA on peripheral B
|
||||
|
@ -1,36 +0,0 @@
|
||||
* Freescale IMX8MM IOMUX Controller
|
||||
|
||||
Please refer to fsl,imx-pinctrl.txt and pinctrl-bindings.txt in this directory
|
||||
for common binding part and usage.
|
||||
|
||||
Required properties:
|
||||
- compatible: "fsl,imx8mm-iomuxc"
|
||||
- reg: should contain the base physical address and size of the iomuxc
|
||||
registers.
|
||||
|
||||
Required properties in sub-nodes:
|
||||
- fsl,pins: each entry consists of 6 integers and represents the mux and config
|
||||
setting for one pin. The first 5 integers <mux_reg conf_reg input_reg mux_val
|
||||
input_val> are specified using a PIN_FUNC_ID macro, which can be found in
|
||||
<arch/arm64/boot/dts/freescale/imx8mm-pinfunc.h>. The last integer CONFIG is
|
||||
the pad setting value like pull-up on this pin. Please refer to i.MX8M Mini
|
||||
Reference Manual for detailed CONFIG settings.
|
||||
|
||||
Examples:
|
||||
|
||||
&uart1 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_uart1>;
|
||||
};
|
||||
|
||||
iomuxc: pinctrl@30330000 {
|
||||
compatible = "fsl,imx8mm-iomuxc";
|
||||
reg = <0x0 0x30330000 0x0 0x10000>;
|
||||
|
||||
pinctrl_uart1: uart1grp {
|
||||
fsl,pins = <
|
||||
MX8MM_IOMUXC_UART1_RXD_UART1_DCE_RX 0x140
|
||||
MX8MM_IOMUXC_UART1_TXD_UART1_DCE_TX 0x140
|
||||
>;
|
||||
};
|
||||
};
|
@ -0,0 +1,82 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pinctrl/fsl,imx8mm-pinctrl.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Freescale IMX8MM IOMUX Controller
|
||||
|
||||
maintainers:
|
||||
- Anson Huang <Anson.Huang@nxp.com>
|
||||
|
||||
description:
|
||||
Please refer to fsl,imx-pinctrl.txt and pinctrl-bindings.txt in this directory
|
||||
for common binding part and usage.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: fsl,imx8mm-iomuxc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
# Client device subnode's properties
|
||||
patternProperties:
|
||||
'grp$':
|
||||
type: object
|
||||
description:
|
||||
Pinctrl node's client devices use subnodes for desired pin configuration.
|
||||
Client device subnodes use below standard properties.
|
||||
|
||||
properties:
|
||||
fsl,pins:
|
||||
description:
|
||||
each entry consists of 6 integers and represents the mux and config
|
||||
setting for one pin. The first 5 integers <mux_reg conf_reg input_reg
|
||||
mux_val input_val> are specified using a PIN_FUNC_ID macro, which can
|
||||
be found in <arch/arm64/boot/dts/freescale/imx8mm-pinfunc.h>. The last
|
||||
integer CONFIG is the pad setting value like pull-up on this pin. Please
|
||||
refer to i.MX8M Mini Reference Manual for detailed CONFIG settings.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32-matrix
|
||||
- items:
|
||||
items:
|
||||
- description: |
|
||||
"mux_reg" indicates the offset of mux register.
|
||||
- description: |
|
||||
"conf_reg" indicates the offset of pad configuration register.
|
||||
- description: |
|
||||
"input_reg" indicates the offset of select input register.
|
||||
- description: |
|
||||
"mux_val" indicates the mux value to be applied.
|
||||
- description: |
|
||||
"input_val" indicates the select input value to be applied.
|
||||
- description: |
|
||||
"pad_setting" indicates the pad configuration value to be applied.
|
||||
|
||||
required:
|
||||
- fsl,pins
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
# Pinmux controller node
|
||||
- |
|
||||
iomuxc: pinctrl@30330000 {
|
||||
compatible = "fsl,imx8mm-iomuxc";
|
||||
reg = <0x30330000 0x10000>;
|
||||
|
||||
pinctrl_uart2: uart2grp {
|
||||
fsl,pins =
|
||||
<0x23C 0x4A4 0x4FC 0x0 0x0 0x140>,
|
||||
<0x240 0x4A8 0x000 0x0 0x0 0x140>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -1,39 +0,0 @@
|
||||
* Freescale IMX8MN IOMUX Controller
|
||||
|
||||
Please refer to fsl,imx-pinctrl.txt and pinctrl-bindings.txt in this directory
|
||||
for common binding part and usage.
|
||||
|
||||
Required properties:
|
||||
- compatible: "fsl,imx8mn-iomuxc"
|
||||
- reg: should contain the base physical address and size of the iomuxc
|
||||
registers.
|
||||
|
||||
Required properties in sub-nodes:
|
||||
- fsl,pins: each entry consists of 6 integers and represents the mux and config
|
||||
setting for one pin. The first 5 integers <mux_reg conf_reg input_reg mux_val
|
||||
input_val> are specified using a PIN_FUNC_ID macro, which can be found in
|
||||
<arch/arm64/boot/dts/freescale/imx8mn-pinfunc.h>. The last integer CONFIG is
|
||||
the pad setting value like pull-up on this pin. Please refer to i.MX8M Nano
|
||||
Reference Manual for detailed CONFIG settings.
|
||||
|
||||
Examples:
|
||||
|
||||
&uart1 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_uart1>;
|
||||
};
|
||||
|
||||
iomuxc: pinctrl@30330000 {
|
||||
compatible = "fsl,imx8mn-iomuxc";
|
||||
reg = <0x0 0x30330000 0x0 0x10000>;
|
||||
|
||||
pinctrl_uart1: uart1grp {
|
||||
fsl,pins = <
|
||||
MX8MN_IOMUXC_UART1_RXD_UART1_DCE_RX 0x140
|
||||
MX8MN_IOMUXC_UART1_TXD_UART1_DCE_TX 0x140
|
||||
MX8MN_IOMUXC_UART3_RXD_UART1_DCE_CTS_B 0x140
|
||||
MX8MN_IOMUXC_UART3_TXD_UART1_DCE_RTS_B 0x140
|
||||
MX8MN_IOMUXC_SD1_DATA4_GPIO2_IO6 0x19
|
||||
>;
|
||||
};
|
||||
};
|
@ -0,0 +1,82 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pinctrl/fsl,imx8mn-pinctrl.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Freescale IMX8MN IOMUX Controller
|
||||
|
||||
maintainers:
|
||||
- Anson Huang <Anson.Huang@nxp.com>
|
||||
|
||||
description:
|
||||
Please refer to fsl,imx-pinctrl.txt and pinctrl-bindings.txt in this directory
|
||||
for common binding part and usage.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: fsl,imx8mn-iomuxc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
# Client device subnode's properties
|
||||
patternProperties:
|
||||
'grp$':
|
||||
type: object
|
||||
description:
|
||||
Pinctrl node's client devices use subnodes for desired pin configuration.
|
||||
Client device subnodes use below standard properties.
|
||||
|
||||
properties:
|
||||
fsl,pins:
|
||||
description:
|
||||
each entry consists of 6 integers and represents the mux and config
|
||||
setting for one pin. The first 5 integers <mux_reg conf_reg input_reg
|
||||
mux_val input_val> are specified using a PIN_FUNC_ID macro, which can
|
||||
be found in <arch/arm64/boot/dts/freescale/imx8mn-pinfunc.h>. The last
|
||||
integer CONFIG is the pad setting value like pull-up on this pin. Please
|
||||
refer to i.MX8M Nano Reference Manual for detailed CONFIG settings.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32-matrix
|
||||
- items:
|
||||
items:
|
||||
- description: |
|
||||
"mux_reg" indicates the offset of mux register.
|
||||
- description: |
|
||||
"conf_reg" indicates the offset of pad configuration register.
|
||||
- description: |
|
||||
"input_reg" indicates the offset of select input register.
|
||||
- description: |
|
||||
"mux_val" indicates the mux value to be applied.
|
||||
- description: |
|
||||
"input_val" indicates the select input value to be applied.
|
||||
- description: |
|
||||
"pad_setting" indicates the pad configuration value to be applied.
|
||||
|
||||
required:
|
||||
- fsl,pins
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
# Pinmux controller node
|
||||
- |
|
||||
iomuxc: pinctrl@30330000 {
|
||||
compatible = "fsl,imx8mn-iomuxc";
|
||||
reg = <0x30330000 0x10000>;
|
||||
|
||||
pinctrl_uart2: uart2grp {
|
||||
fsl,pins =
|
||||
<0x23C 0x4A4 0x4FC 0x0 0x0 0x140>,
|
||||
<0x240 0x4A8 0x000 0x0 0x0 0x140>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -30,8 +30,6 @@ patternProperties:
|
||||
|
||||
properties:
|
||||
fsl,pins:
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
description:
|
||||
each entry consists of 6 integers and represents the mux and config
|
||||
setting for one pin. The first 5 integers <mux_reg conf_reg input_reg
|
||||
@ -39,6 +37,22 @@ patternProperties:
|
||||
be found in <arch/arm64/boot/dts/freescale/imx8mp-pinfunc.h>. The last
|
||||
integer CONFIG is the pad setting value like pull-up on this pin. Please
|
||||
refer to i.MX8M Plus Reference Manual for detailed CONFIG settings.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32-matrix
|
||||
- items:
|
||||
items:
|
||||
- description: |
|
||||
"mux_reg" indicates the offset of mux register.
|
||||
- description: |
|
||||
"conf_reg" indicates the offset of pad configuration register.
|
||||
- description: |
|
||||
"input_reg" indicates the offset of select input register.
|
||||
- description: |
|
||||
"mux_val" indicates the mux value to be applied.
|
||||
- description: |
|
||||
"input_val" indicates the select input value to be applied.
|
||||
- description: |
|
||||
"pad_setting" indicates the pad configuration value to be applied.
|
||||
|
||||
required:
|
||||
- fsl,pins
|
||||
@ -59,10 +73,9 @@ examples:
|
||||
reg = <0x30330000 0x10000>;
|
||||
|
||||
pinctrl_uart2: uart2grp {
|
||||
fsl,pins = <
|
||||
0x228 0x488 0x5F0 0x0 0x6 0x49
|
||||
0x228 0x488 0x000 0x0 0x0 0x49
|
||||
>;
|
||||
fsl,pins =
|
||||
<0x228 0x488 0x5F0 0x0 0x6 0x49>,
|
||||
<0x228 0x488 0x000 0x0 0x0 0x49>;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1,36 +0,0 @@
|
||||
* Freescale IMX8MQ IOMUX Controller
|
||||
|
||||
Please refer to fsl,imx-pinctrl.txt and pinctrl-bindings.txt in this directory
|
||||
for common binding part and usage.
|
||||
|
||||
Required properties:
|
||||
- compatible: "fsl,imx8mq-iomuxc"
|
||||
- reg: should contain the base physical address and size of the iomuxc
|
||||
registers.
|
||||
|
||||
Required properties in sub-nodes:
|
||||
- fsl,pins: each entry consists of 6 integers and represents the mux and config
|
||||
setting for one pin. The first 5 integers <mux_reg conf_reg input_reg mux_val
|
||||
input_val> are specified using a PIN_FUNC_ID macro, which can be found in
|
||||
imx8mq-pinfunc.h under device tree source folder. The last integer CONFIG is
|
||||
the pad setting value like pull-up on this pin. Please refer to i.MX8M Quad
|
||||
Reference Manual for detailed CONFIG settings.
|
||||
|
||||
Examples:
|
||||
|
||||
&uart1 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_uart1>;
|
||||
};
|
||||
|
||||
iomuxc: pinctrl@30330000 {
|
||||
compatible = "fsl,imx8mq-iomuxc";
|
||||
reg = <0x0 0x30330000 0x0 0x10000>;
|
||||
|
||||
pinctrl_uart1: uart1grp {
|
||||
fsl,pins = <
|
||||
MX8MQ_IOMUXC_UART1_RXD_UART1_DCE_RX 0x49
|
||||
MX8MQ_IOMUXC_UART1_TXD_UART1_DCE_TX 0x49
|
||||
>;
|
||||
};
|
||||
};
|
@ -0,0 +1,82 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pinctrl/fsl,imx8mq-pinctrl.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Freescale IMX8MQ IOMUX Controller
|
||||
|
||||
maintainers:
|
||||
- Anson Huang <Anson.Huang@nxp.com>
|
||||
|
||||
description:
|
||||
Please refer to fsl,imx-pinctrl.txt and pinctrl-bindings.txt in this directory
|
||||
for common binding part and usage.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: fsl,imx8mq-iomuxc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
# Client device subnode's properties
|
||||
patternProperties:
|
||||
'grp$':
|
||||
type: object
|
||||
description:
|
||||
Pinctrl node's client devices use subnodes for desired pin configuration.
|
||||
Client device subnodes use below standard properties.
|
||||
|
||||
properties:
|
||||
fsl,pins:
|
||||
description:
|
||||
each entry consists of 6 integers and represents the mux and config
|
||||
setting for one pin. The first 5 integers <mux_reg conf_reg input_reg
|
||||
mux_val input_val> are specified using a PIN_FUNC_ID macro, which can
|
||||
be found in <arch/arm64/boot/dts/freescale/imx8mq-pinfunc.h>. The last
|
||||
integer CONFIG is the pad setting value like pull-up on this pin. Please
|
||||
refer to i.MX8M Quad Reference Manual for detailed CONFIG settings.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32-matrix
|
||||
- items:
|
||||
items:
|
||||
- description: |
|
||||
"mux_reg" indicates the offset of mux register.
|
||||
- description: |
|
||||
"conf_reg" indicates the offset of pad configuration register.
|
||||
- description: |
|
||||
"input_reg" indicates the offset of select input register.
|
||||
- description: |
|
||||
"mux_val" indicates the mux value to be applied.
|
||||
- description: |
|
||||
"input_val" indicates the select input value to be applied.
|
||||
- description: |
|
||||
"pad_setting" indicates the pad configuration value to be applied.
|
||||
|
||||
required:
|
||||
- fsl,pins
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
# Pinmux controller node
|
||||
- |
|
||||
iomuxc: pinctrl@30330000 {
|
||||
compatible = "fsl,imx8mq-iomuxc";
|
||||
reg = <0x30330000 0x10000>;
|
||||
|
||||
pinctrl_uart1: uart1grp {
|
||||
fsl,pins =
|
||||
<0x234 0x49C 0x4F4 0x0 0x0 0x49>,
|
||||
<0x238 0x4A0 0x4F4 0x0 0x0 0x49>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -0,0 +1,153 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pinctrl/qcom,ipq6018-pinctrl.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Technologies, Inc. IPQ6018 TLMM block
|
||||
|
||||
maintainers:
|
||||
- Sricharan R <sricharan@codeaurora.org>
|
||||
|
||||
description: |
|
||||
This binding describes the Top Level Mode Multiplexer block found in the
|
||||
IPQ6018 platform.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,ipq6018-pinctrl
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
description: Specifies the TLMM summary IRQ
|
||||
maxItems: 1
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
'#interrupt-cells':
|
||||
description:
|
||||
Specifies the PIN numbers and Flags, as defined in defined in
|
||||
include/dt-bindings/interrupt-controller/irq.h
|
||||
const: 2
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
'#gpio-cells':
|
||||
description: Specifying the pin number and flags, as defined in
|
||||
include/dt-bindings/gpio/gpio.h
|
||||
const: 2
|
||||
|
||||
gpio-ranges:
|
||||
maxItems: 1
|
||||
|
||||
#PIN CONFIGURATION NODES
|
||||
patternProperties:
|
||||
'-pinmux$':
|
||||
type: object
|
||||
description:
|
||||
Pinctrl node's client devices use subnodes for desired pin configuration.
|
||||
Client device subnodes use below standard properties.
|
||||
allOf:
|
||||
- $ref: "/schemas/pinctrl/pincfg-node.yaml"
|
||||
|
||||
properties:
|
||||
pins:
|
||||
description:
|
||||
List of gpio pins affected by the properties specified in this
|
||||
subnode.
|
||||
items:
|
||||
oneOf:
|
||||
- pattern: "^gpio([1-9]|[1-7][0-9]|80)$"
|
||||
- enum: [ sdc1_clk, sdc1_cmd, sdc1_data, sdc2_clk, sdc2_cmd,
|
||||
sdc2_data, qdsd_cmd, qdsd_data0, qdsd_data1, qdsd_data2,
|
||||
qdsd_data3 ]
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
|
||||
function:
|
||||
description:
|
||||
Specify the alternative function to be configured for the specified
|
||||
pins.
|
||||
enum: [ adsp_ext, alsp_int, atest_bbrx0, atest_bbrx1, atest_char,
|
||||
atest_char0, atest_char1, atest_char2, atest_char3, atest_combodac,
|
||||
atest_gpsadc0, atest_gpsadc1, atest_tsens, atest_wlan0,
|
||||
atest_wlan1, backlight_en, bimc_dte0, bimc_dte1, blsp1_i2c,
|
||||
blsp2_i2c, blsp3_i2c, blsp4_i2c, blsp5_i2c, blsp6_i2c, blsp1_spi,
|
||||
blsp1_spi_cs1, blsp1_spi_cs2, blsp1_spi_cs3, blsp2_spi,
|
||||
blsp2_spi_cs1, blsp2_spi_cs2, blsp2_spi_cs3, blsp3_spi,
|
||||
blsp3_spi_cs1, blsp3_spi_cs2, blsp3_spi_cs3, blsp4_spi, blsp5_spi,
|
||||
blsp6_spi, blsp1_uart, blsp2_uart, blsp1_uim, blsp2_uim, cam1_rst,
|
||||
cam1_standby, cam_mclk0, cam_mclk1, cci_async, cci_i2c, cci_timer0,
|
||||
cci_timer1, cci_timer2, cdc_pdm0, codec_mad, dbg_out, display_5v,
|
||||
dmic0_clk, dmic0_data, dsi_rst, ebi0_wrcdc, euro_us, ext_lpass,
|
||||
flash_strobe, gcc_gp1_clk_a, gcc_gp1_clk_b, gcc_gp2_clk_a,
|
||||
gcc_gp2_clk_b, gcc_gp3_clk_a, gcc_gp3_clk_b, gpio, gsm0_tx0,
|
||||
gsm0_tx1, gsm1_tx0, gsm1_tx1, gyro_accl, kpsns0, kpsns1, kpsns2,
|
||||
ldo_en, ldo_update, mag_int, mdp_vsync, modem_tsync, m_voc,
|
||||
nav_pps, nav_tsync, pa_indicator, pbs0, pbs1, pbs2, pri_mi2s,
|
||||
pri_mi2s_ws, prng_rosc, pwr_crypto_enabled_a, pwr_crypto_enabled_b,
|
||||
pwr_modem_enabled_a, pwr_modem_enabled_b, pwr_nav_enabled_a,
|
||||
pwr_nav_enabled_b, qdss_ctitrig_in_a0, qdss_ctitrig_in_a1,
|
||||
qdss_ctitrig_in_b0, qdss_ctitrig_in_b1, qdss_ctitrig_out_a0,
|
||||
qdss_ctitrig_out_a1, qdss_ctitrig_out_b0, qdss_ctitrig_out_b1,
|
||||
qdss_traceclk_a, qdss_traceclk_b, qdss_tracectl_a, qdss_tracectl_b,
|
||||
qdss_tracedata_a, qdss_tracedata_b, reset_n, sd_card, sd_write,
|
||||
sec_mi2s, smb_int, ssbi_wtr0, ssbi_wtr1, uim1, uim2, uim3,
|
||||
uim_batt, wcss_bt, wcss_fm, wcss_wlan, webcam1_rst ]
|
||||
|
||||
drive-strength:
|
||||
enum: [2, 4, 6, 8, 10, 12, 14, 16]
|
||||
default: 2
|
||||
description:
|
||||
Selects the drive strength for the specified pins, in mA.
|
||||
|
||||
bias-pull-down: true
|
||||
|
||||
bias-pull-up: true
|
||||
|
||||
bias-disable: true
|
||||
|
||||
output-high: true
|
||||
|
||||
output-low: true
|
||||
|
||||
required:
|
||||
- pins
|
||||
- function
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- interrupt-controller
|
||||
- '#interrupt-cells'
|
||||
- gpio-controller
|
||||
- '#gpio-cells'
|
||||
- gpio-ranges
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
tlmm: pinctrl@1000000 {
|
||||
compatible = "qcom,ipq6018-pinctrl";
|
||||
reg = <0x01000000 0x300000>;
|
||||
interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
gpio-ranges = <&tlmm 0 80>;
|
||||
|
||||
serial3-pinmux {
|
||||
pins = "gpio44", "gpio45";
|
||||
function = "blsp2_uart";
|
||||
drive-strength = <8>;
|
||||
bias-pull-down;
|
||||
};
|
||||
};
|
@ -0,0 +1,324 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/remoteproc/ti,omap-remoteproc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: OMAP4+ Remoteproc Devices
|
||||
|
||||
maintainers:
|
||||
- Suman Anna <s-anna@ti.com>
|
||||
|
||||
description:
|
||||
The OMAP family of SoCs usually have one or more slave processor sub-systems
|
||||
that are used to offload some of the processor-intensive tasks, or to manage
|
||||
other hardware accelerators, for achieving various system level goals.
|
||||
|
||||
The processor cores in the sub-system are usually behind an IOMMU, and may
|
||||
contain additional sub-modules like Internal RAM and/or ROMs, L1 and/or L2
|
||||
caches, an Interrupt Controller, a Cache Controller etc.
|
||||
|
||||
The OMAP SoCs usually have a DSP processor sub-system and/or an IPU processor
|
||||
sub-system. The DSP processor sub-system can contain any of the TI's C64x,
|
||||
C66x or C67x family of DSP cores as the main execution unit. The IPU processor
|
||||
sub-system usually contains either a Dual-Core Cortex-M3 or Dual-Core
|
||||
Cortex-M4 processors.
|
||||
|
||||
Each remote processor sub-system is represented as a single DT node. Each node
|
||||
has a number of required or optional properties that enable the OS running on
|
||||
the host processor (MPU) to perform the device management of the remote
|
||||
processor and to communicate with the remote processor. The various properties
|
||||
can be classified as constant or variable. The constant properties are
|
||||
dictated by the SoC and does not change from one board to another having the
|
||||
same SoC. Examples of constant properties include 'iommus', 'reg'. The
|
||||
variable properties are dictated by the system integration aspects such as
|
||||
memory on the board, or configuration used within the corresponding firmware
|
||||
image. Examples of variable properties include 'mboxes', 'memory-region',
|
||||
'timers', 'watchdog-timers' etc.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,omap4-dsp
|
||||
- ti,omap5-dsp
|
||||
- ti,dra7-dsp
|
||||
- ti,omap4-ipu
|
||||
- ti,omap5-ipu
|
||||
- ti,dra7-ipu
|
||||
|
||||
iommus:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
description: |
|
||||
phandles to OMAP IOMMU nodes, that need to be programmed
|
||||
for this remote processor to access any external RAM memory or
|
||||
other peripheral device address spaces. This property usually
|
||||
has only a single phandle. Multiple phandles are used only in
|
||||
cases where the sub-system has different ports for different
|
||||
sub-modules within the processor sub-system (eg: DRA7 DSPs),
|
||||
and need the same programming in both the MMUs.
|
||||
|
||||
mboxes:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
description: |
|
||||
OMAP Mailbox specifier denoting the sub-mailbox, to be used for
|
||||
communication with the remote processor. The specifier format is
|
||||
as per the bindings,
|
||||
Documentation/devicetree/bindings/mailbox/omap-mailbox.txt
|
||||
This property should match with the sub-mailbox node used in
|
||||
the firmware image.
|
||||
|
||||
clocks:
|
||||
description: |
|
||||
Main functional clock for the remote processor
|
||||
|
||||
resets:
|
||||
description: |
|
||||
Reset handles for the remote processor
|
||||
|
||||
firmware-name:
|
||||
description: |
|
||||
Default name of the firmware to load to the remote processor.
|
||||
|
||||
# Optional properties:
|
||||
# --------------------
|
||||
# Some of these properties are mandatory on some SoCs, and some are optional
|
||||
# depending on the configuration of the firmware image to be executed on the
|
||||
# remote processor. The conditions are mentioned for each property.
|
||||
#
|
||||
# The following are the optional properties:
|
||||
|
||||
memory-region:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: |
|
||||
phandle to the reserved memory node to be associated
|
||||
with the remoteproc device. The reserved memory node
|
||||
can be a CMA memory node, and should be defined as
|
||||
per the bindings,
|
||||
Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt
|
||||
|
||||
reg:
|
||||
description: |
|
||||
Address space for any remoteproc memories present on
|
||||
the SoC. Should contain an entry for each value in
|
||||
'reg-names'. These are mandatory for all DSP and IPU
|
||||
processors that have them (OMAP4/OMAP5 DSPs do not have
|
||||
any RAMs)
|
||||
|
||||
reg-names:
|
||||
description: |
|
||||
Required names for each of the address spaces defined in
|
||||
the 'reg' property. Expects the names from the following
|
||||
list, in the specified order, each representing the corresponding
|
||||
internal RAM memory region.
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
items:
|
||||
- const: l2ram
|
||||
- const: l1pram
|
||||
- const: l1dram
|
||||
|
||||
ti,bootreg:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
description: |
|
||||
Should be a triple of the phandle to the System Control
|
||||
Configuration region that contains the boot address
|
||||
register, the register offset of the boot address
|
||||
register within the System Control module, and the bit
|
||||
shift within the register. This property is required for
|
||||
all the DSP instances on OMAP4, OMAP5 and DRA7xx SoCs.
|
||||
|
||||
ti,autosuspend-delay-ms:
|
||||
description: |
|
||||
Custom autosuspend delay for the remoteproc in milliseconds.
|
||||
Recommended values is preferable to be in the order of couple
|
||||
of seconds. A negative value can also be used to disable the
|
||||
autosuspend behavior.
|
||||
|
||||
ti,timers:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
description: |
|
||||
One or more phandles to OMAP DMTimer nodes, that serve
|
||||
as System/Tick timers for the OS running on the remote
|
||||
processors. This will usually be a single timer if the
|
||||
processor sub-system is running in SMP mode, or one per
|
||||
core in the processor sub-system. This can also be used
|
||||
to reserve specific timers to be dedicated to the
|
||||
remote processors.
|
||||
|
||||
This property is mandatory on remote processors requiring
|
||||
external tick wakeup, and to support Power Management
|
||||
features. The timers to be used should match with the
|
||||
timers used in the firmware image.
|
||||
|
||||
ti,watchdog-timers:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
description: |
|
||||
One or more phandles to OMAP DMTimer nodes, used to
|
||||
serve as Watchdog timers for the processor cores. This
|
||||
will usually be one per executing processor core, even
|
||||
if the processor sub-system is running a SMP OS.
|
||||
|
||||
The timers to be used should match with the watchdog
|
||||
timers used in the firmware image.
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,dra7-dsp
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
required:
|
||||
- reg
|
||||
- reg-names
|
||||
- ti,bootreg
|
||||
|
||||
else:
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,omap4-ipu
|
||||
- ti,omap5-ipu
|
||||
- ti,dra7-ipu
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 1
|
||||
maxItems: 1
|
||||
ti,bootreg: false
|
||||
required:
|
||||
- reg
|
||||
- reg-names
|
||||
|
||||
else:
|
||||
properties:
|
||||
reg: false
|
||||
required:
|
||||
- ti,bootreg
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- iommus
|
||||
- mboxes
|
||||
- clocks
|
||||
- resets
|
||||
- firmware-name
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
||||
//Example 1: OMAP4 DSP
|
||||
|
||||
/* DSP Reserved Memory node */
|
||||
#include <dt-bindings/clock/omap4.h>
|
||||
reserved-memory {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
dsp_memory_region: dsp-memory@98000000 {
|
||||
compatible = "shared-dma-pool";
|
||||
reg = <0x98000000 0x800000>;
|
||||
reusable;
|
||||
};
|
||||
};
|
||||
|
||||
/* DSP node */
|
||||
ocp {
|
||||
dsp: dsp {
|
||||
compatible = "ti,omap4-dsp";
|
||||
ti,bootreg = <&scm_conf 0x304 0>;
|
||||
iommus = <&mmu_dsp>;
|
||||
mboxes = <&mailbox &mbox_dsp>;
|
||||
memory-region = <&dsp_memory_region>;
|
||||
ti,timers = <&timer5>;
|
||||
ti,watchdog-timers = <&timer6>;
|
||||
clocks = <&tesla_clkctrl OMAP4_DSP_CLKCTRL 0>;
|
||||
resets = <&prm_tesla 0>, <&prm_tesla 1>;
|
||||
firmware-name = "omap4-dsp-fw.xe64T";
|
||||
};
|
||||
};
|
||||
|
||||
- |+
|
||||
|
||||
//Example 2: OMAP5 IPU
|
||||
|
||||
/* IPU Reserved Memory node */
|
||||
#include <dt-bindings/clock/omap5.h>
|
||||
reserved-memory {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
ipu_memory_region: ipu-memory@95800000 {
|
||||
compatible = "shared-dma-pool";
|
||||
reg = <0 0x95800000 0 0x3800000>;
|
||||
reusable;
|
||||
};
|
||||
};
|
||||
|
||||
/* IPU node */
|
||||
ocp {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
ipu: ipu@55020000 {
|
||||
compatible = "ti,omap5-ipu";
|
||||
reg = <0x55020000 0x10000>;
|
||||
reg-names = "l2ram";
|
||||
iommus = <&mmu_ipu>;
|
||||
mboxes = <&mailbox &mbox_ipu>;
|
||||
memory-region = <&ipu_memory_region>;
|
||||
ti,timers = <&timer3>, <&timer4>;
|
||||
ti,watchdog-timers = <&timer9>, <&timer11>;
|
||||
clocks = <&ipu_clkctrl OMAP5_MMU_IPU_CLKCTRL 0>;
|
||||
resets = <&prm_core 2>;
|
||||
firmware-name = "omap5-ipu-fw.xem4";
|
||||
};
|
||||
};
|
||||
|
||||
- |+
|
||||
|
||||
//Example 3: DRA7xx/AM57xx DSP
|
||||
|
||||
/* DSP1 Reserved Memory node */
|
||||
#include <dt-bindings/clock/dra7.h>
|
||||
reserved-memory {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
dsp1_memory_region: dsp1-memory@99000000 {
|
||||
compatible = "shared-dma-pool";
|
||||
reg = <0x0 0x99000000 0x0 0x4000000>;
|
||||
reusable;
|
||||
};
|
||||
};
|
||||
|
||||
/* DSP1 node */
|
||||
ocp {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
dsp1: dsp@40800000 {
|
||||
compatible = "ti,dra7-dsp";
|
||||
reg = <0x40800000 0x48000>,
|
||||
<0x40e00000 0x8000>,
|
||||
<0x40f00000 0x8000>;
|
||||
reg-names = "l2ram", "l1pram", "l1dram";
|
||||
ti,bootreg = <&scm_conf 0x55c 0>;
|
||||
iommus = <&mmu0_dsp1>, <&mmu1_dsp1>;
|
||||
mboxes = <&mailbox5 &mbox_dsp1_ipc3x>;
|
||||
memory-region = <&dsp1_memory_region>;
|
||||
ti,timers = <&timer5>;
|
||||
ti,watchdog-timers = <&timer10>;
|
||||
resets = <&prm_dsp1 0>;
|
||||
clocks = <&dsp1_clkctrl DRA7_DSP1_MMU0_DSP1_CLKCTRL 0>;
|
||||
firmware-name = "dra7-dsp1-fw.xe66";
|
||||
};
|
||||
};
|
113
Documentation/devicetree/bindings/sound/amlogic,aiu.yaml
Normal file
113
Documentation/devicetree/bindings/sound/amlogic,aiu.yaml
Normal file
@ -0,0 +1,113 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/amlogic,aiu.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Amlogic AIU audio output controller
|
||||
|
||||
maintainers:
|
||||
- Jerome Brunet <jbrunet@baylibre.com>
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^audio-controller@.*"
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 2
|
||||
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- amlogic,aiu-gxbb
|
||||
- amlogic,aiu-gxl
|
||||
- amlogic,aiu-meson8
|
||||
- amlogic,aiu-meson8b
|
||||
- const:
|
||||
amlogic,aiu
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: AIU peripheral clock
|
||||
- description: I2S peripheral clock
|
||||
- description: I2S output clock
|
||||
- description: I2S master clock
|
||||
- description: I2S mixer clock
|
||||
- description: SPDIF peripheral clock
|
||||
- description: SPDIF output clock
|
||||
- description: SPDIF master clock
|
||||
- description: SPDIF master clock multiplexer
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: pclk
|
||||
- const: i2s_pclk
|
||||
- const: i2s_aoclk
|
||||
- const: i2s_mclk
|
||||
- const: i2s_mixer
|
||||
- const: spdif_pclk
|
||||
- const: spdif_aoclk
|
||||
- const: spdif_mclk
|
||||
- const: spdif_mclk_sel
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
- description: I2S interrupt line
|
||||
- description: SPDIF interrupt line
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: i2s
|
||||
- const: spdif
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- "#sound-dai-cells"
|
||||
- compatible
|
||||
- clocks
|
||||
- clock-names
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- reg
|
||||
- resets
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/gxbb-clkc.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/reset/amlogic,meson-gxbb-reset.h>
|
||||
|
||||
aiu: audio-controller@5400 {
|
||||
compatible = "amlogic,aiu-gxl", "amlogic,aiu";
|
||||
#sound-dai-cells = <2>;
|
||||
reg = <0x0 0x5400 0x0 0x2ac>;
|
||||
interrupts = <GIC_SPI 48 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 50 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-names = "i2s", "spdif";
|
||||
clocks = <&clkc CLKID_AIU_GLUE>,
|
||||
<&clkc CLKID_I2S_OUT>,
|
||||
<&clkc CLKID_AOCLK_GATE>,
|
||||
<&clkc CLKID_CTS_AMCLK>,
|
||||
<&clkc CLKID_MIXER_IFACE>,
|
||||
<&clkc CLKID_IEC958>,
|
||||
<&clkc CLKID_IEC958_GATE>,
|
||||
<&clkc CLKID_CTS_MCLK_I958>,
|
||||
<&clkc CLKID_CTS_I958>;
|
||||
clock-names = "pclk",
|
||||
"i2s_pclk",
|
||||
"i2s_aoclk",
|
||||
"i2s_mclk",
|
||||
"i2s_mixer",
|
||||
"spdif_pclk",
|
||||
"spdif_aoclk",
|
||||
"spdif_mclk",
|
||||
"spdif_mclk_sel";
|
||||
resets = <&reset RESET_AIU>;
|
||||
};
|
||||
|
@ -0,0 +1,51 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/amlogic,g12a-toacodec.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Amlogic G12a Internal DAC Control Glue
|
||||
|
||||
maintainers:
|
||||
- Jerome Brunet <jbrunet@baylibre.com>
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^audio-controller@.*"
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 1
|
||||
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- const:
|
||||
amlogic,g12a-toacodec
|
||||
- items:
|
||||
- enum:
|
||||
- amlogic,sm1-toacodec
|
||||
- const:
|
||||
amlogic,g12a-toacodec
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- "#sound-dai-cells"
|
||||
- compatible
|
||||
- reg
|
||||
- resets
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/reset/amlogic,meson-g12a-audio-reset.h>
|
||||
|
||||
toacodec: audio-controller@740 {
|
||||
compatible = "amlogic,g12a-toacodec";
|
||||
reg = <0x0 0x740 0x0 0x4>;
|
||||
#sound-dai-cells = <1>;
|
||||
resets = <&clkc_audio AUD_RESET_TOACODEC>;
|
||||
};
|
@ -0,0 +1,113 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/amlogic,gx-sound-card.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Amlogic GX sound card
|
||||
|
||||
maintainers:
|
||||
- Jerome Brunet <jbrunet@baylibre.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: amlogic,gx-sound-card
|
||||
|
||||
audio-aux-devs:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
description: list of auxiliary devices
|
||||
|
||||
audio-routing:
|
||||
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
|
||||
minItems: 2
|
||||
description: |-
|
||||
A list of the connections between audio components. Each entry is a
|
||||
pair of strings, the first being the connection's sink, the second
|
||||
being the connection's source.
|
||||
|
||||
audio-widgets:
|
||||
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
|
||||
minItems: 2
|
||||
description: |-
|
||||
A list off component DAPM widget. Each entry is a pair of strings,
|
||||
the first being the widget type, the second being the widget name
|
||||
|
||||
model:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
description: User specified audio sound card name
|
||||
|
||||
patternProperties:
|
||||
"^dai-link-[0-9]+$":
|
||||
type: object
|
||||
description: |-
|
||||
dai-link child nodes:
|
||||
Container for dai-link level properties and the CODEC sub-nodes.
|
||||
There should be at least one (and probably more) subnode of this type
|
||||
|
||||
properties:
|
||||
dai-format:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
enum: [ i2s, left-j, dsp_a ]
|
||||
|
||||
mclk-fs:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |-
|
||||
Multiplication factor between the frame rate and master clock
|
||||
rate
|
||||
|
||||
sound-dai:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: phandle of the CPU DAI
|
||||
|
||||
patternProperties:
|
||||
"^codec-[0-9]+$":
|
||||
type: object
|
||||
description: |-
|
||||
Codecs:
|
||||
dai-link representing backend links should have at least one subnode.
|
||||
One subnode for each codec of the dai-link. dai-link representing
|
||||
frontend links have no codec, therefore have no subnodes
|
||||
|
||||
properties:
|
||||
sound-dai:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: phandle of the codec DAI
|
||||
|
||||
required:
|
||||
- sound-dai
|
||||
|
||||
required:
|
||||
- sound-dai
|
||||
|
||||
required:
|
||||
- model
|
||||
- dai-link-0
|
||||
|
||||
examples:
|
||||
- |
|
||||
sound {
|
||||
compatible = "amlogic,gx-sound-card";
|
||||
model = "GXL-ACME-S905X-FOO";
|
||||
audio-aux-devs = <&>;
|
||||
audio-routing = "I2S ENCODER I2S IN", "I2S FIFO Playback";
|
||||
|
||||
dai-link-0 {
|
||||
sound-dai = <&i2s_fifo>;
|
||||
};
|
||||
|
||||
dai-link-1 {
|
||||
sound-dai = <&i2s_encoder>;
|
||||
dai-format = "i2s";
|
||||
mclk-fs = <256>;
|
||||
|
||||
codec-0 {
|
||||
sound-dai = <&codec0>;
|
||||
};
|
||||
|
||||
codec-1 {
|
||||
sound-dai = <&codec1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
58
Documentation/devicetree/bindings/sound/amlogic,t9015.yaml
Normal file
58
Documentation/devicetree/bindings/sound/amlogic,t9015.yaml
Normal file
@ -0,0 +1,58 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/amlogic,t9015.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Amlogic T9015 Internal Audio DAC
|
||||
|
||||
maintainers:
|
||||
- Jerome Brunet <jbrunet@baylibre.com>
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^audio-controller@.*"
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
compatible:
|
||||
items:
|
||||
- const: amlogic,t9015
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Peripheral clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: pclk
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- "#sound-dai-cells"
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/g12a-clkc.h>
|
||||
#include <dt-bindings/reset/amlogic,meson-g12a-reset.h>
|
||||
|
||||
acodec: audio-controller@32000 {
|
||||
compatible = "amlogic,t9015";
|
||||
reg = <0x0 0x32000 0x0 0x14>;
|
||||
#sound-dai-cells = <0>;
|
||||
clocks = <&clkc CLKID_AUDIO_CODEC>;
|
||||
clock-names = "pclk";
|
||||
resets = <&reset RESET_AUDIO_CODEC>;
|
||||
};
|
||||
|
@ -0,0 +1,29 @@
|
||||
Broadcom DSL/PON BCM63xx Audio I2S controller
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "brcm,bcm63xx-i2s".
|
||||
- #address-cells: 32bit valued, 1 cell.
|
||||
- #size-cells: 32bit valued, 0 cell.
|
||||
- reg: Should contain audio registers location and length
|
||||
- interrupts: Should contain the interrupt for the controller.
|
||||
- clocks: Must contain an entry for each entry in clock-names.
|
||||
Please refer to clock-bindings.txt.
|
||||
- clock-names: One of each entry matching the clocks phandles list:
|
||||
- "i2sclk" (generated clock) Required.
|
||||
- "i2sosc" (fixed 200MHz clock) Required.
|
||||
|
||||
(1) : The generated clock is required only when any of TX and RX
|
||||
works on Master Mode.
|
||||
(2) : The fixed 200MHz clock is from internal chip and always on
|
||||
|
||||
Example:
|
||||
|
||||
i2s: bcm63xx-i2s {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "brcm,bcm63xx-i2s";
|
||||
reg = <0xFF802080 0xFF>;
|
||||
interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&i2sclk>, <&osc>;
|
||||
clock-names = "i2sclk","i2sosc";
|
||||
};
|
69
Documentation/devicetree/bindings/sound/cirrus,cs42l51.yaml
Normal file
69
Documentation/devicetree/bindings/sound/cirrus,cs42l51.yaml
Normal file
@ -0,0 +1,69 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/cirrus,cs42l51.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: CS42L51 audio codec DT bindings
|
||||
|
||||
maintainers:
|
||||
- Olivier Moysan <olivier.moysan@st.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: cirrus,cs42l51
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: MCLK
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
VL-supply:
|
||||
description: phandle to voltage regulator of digital interface section
|
||||
|
||||
VD-supply:
|
||||
description: phandle to voltage regulator of digital internal section
|
||||
|
||||
VA-supply:
|
||||
description: phandle to voltage regulator of analog internal section
|
||||
|
||||
VAHP-supply:
|
||||
description: phandle to voltage regulator of headphone
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#sound-dai-cells"
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
i2c@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
cs42l51@4a {
|
||||
compatible = "cirrus,cs42l51";
|
||||
reg = <0x4a>;
|
||||
#sound-dai-cells = <0>;
|
||||
clocks = <&mclk_prov>;
|
||||
clock-names = "MCLK";
|
||||
VL-supply = <®_audio>;
|
||||
VD-supply = <®_audio>;
|
||||
VA-supply = <®_audio>;
|
||||
VAHP-supply = <®_audio>;
|
||||
reset-gpios = <&gpiog 9 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
...
|
@ -1,33 +0,0 @@
|
||||
CS42L51 audio CODEC
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "cirrus,cs42l51"
|
||||
|
||||
- reg : the I2C address of the device for I2C.
|
||||
|
||||
Optional properties:
|
||||
- VL-supply, VD-supply, VA-supply, VAHP-supply: power supplies for the device,
|
||||
as covered in Documentation/devicetree/bindings/regulator/regulator.txt.
|
||||
|
||||
- reset-gpios : GPIO specification for the reset pin. If specified, it will be
|
||||
deasserted before starting the communication with the codec.
|
||||
|
||||
- clocks : a list of phandles + clock-specifiers, one for each entry in
|
||||
clock-names
|
||||
|
||||
- clock-names : must contain "MCLK"
|
||||
|
||||
Example:
|
||||
|
||||
cs42l51: cs42l51@4a {
|
||||
compatible = "cirrus,cs42l51";
|
||||
reg = <0x4a>;
|
||||
clocks = <&mclk_prov>;
|
||||
clock-names = "MCLK";
|
||||
VL-supply = <®_audio>;
|
||||
VD-supply = <®_audio>;
|
||||
VA-supply = <®_audio>;
|
||||
VAHP-supply = <®_audio>;
|
||||
reset-gpios = <&gpiog 9 GPIO_ACTIVE_LOW>;
|
||||
};
|
@ -1,44 +0,0 @@
|
||||
Audio codec controlled by ChromeOS EC
|
||||
|
||||
Google's ChromeOS EC codec is a digital mic codec provided by the
|
||||
Embedded Controller (EC) and is controlled via a host-command interface.
|
||||
|
||||
An EC codec node should only be found as a sub-node of the EC node (see
|
||||
Documentation/devicetree/bindings/mfd/cros-ec.txt).
|
||||
|
||||
Required properties:
|
||||
- compatible: Must contain "google,cros-ec-codec"
|
||||
- #sound-dai-cells: Should be 1. The cell specifies number of DAIs.
|
||||
|
||||
Optional properties:
|
||||
- reg: Pysical base address and length of shared memory region from EC.
|
||||
It contains 3 unsigned 32-bit integer. The first 2 integers
|
||||
combine to become an unsigned 64-bit physical address. The last
|
||||
one integer is length of the shared memory.
|
||||
- memory-region: Shared memory region to EC. A "shared-dma-pool". See
|
||||
../reserved-memory/reserved-memory.txt for details.
|
||||
|
||||
Example:
|
||||
|
||||
{
|
||||
...
|
||||
|
||||
reserved_mem: reserved_mem {
|
||||
compatible = "shared-dma-pool";
|
||||
reg = <0 0x52800000 0 0x100000>;
|
||||
no-map;
|
||||
};
|
||||
}
|
||||
|
||||
cros-ec@0 {
|
||||
compatible = "google,cros-ec-spi";
|
||||
|
||||
...
|
||||
|
||||
cros_ec_codec: ec-codec {
|
||||
compatible = "google,cros-ec-codec";
|
||||
#sound-dai-cells = <1>;
|
||||
reg = <0x0 0x10500000 0x80000>;
|
||||
memory-region = <&reserved_mem>;
|
||||
};
|
||||
};
|
@ -0,0 +1,67 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/google,cros-ec-codec.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Audio codec controlled by ChromeOS EC
|
||||
|
||||
maintainers:
|
||||
- Cheng-Yi Chiang <cychiang@chromium.org>
|
||||
|
||||
description: |
|
||||
Google's ChromeOS EC codec is a digital mic codec provided by the
|
||||
Embedded Controller (EC) and is controlled via a host-command interface.
|
||||
An EC codec node should only be found as a sub-node of the EC node (see
|
||||
Documentation/devicetree/bindings/mfd/cros-ec.txt).
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: google,cros-ec-codec
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: |
|
||||
Physical base address and length of shared memory region from EC.
|
||||
It contains 3 unsigned 32-bit integer. The first 2 integers
|
||||
combine to become an unsigned 64-bit physical address.
|
||||
The last one integer is the length of the shared memory.
|
||||
|
||||
memory-region:
|
||||
$ref: '/schemas/types.yaml#/definitions/phandle'
|
||||
description: |
|
||||
Shared memory region to EC. A "shared-dma-pool".
|
||||
See ../reserved-memory/reserved-memory.txt for details.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- '#sound-dai-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
reserved_mem: reserved-mem@52800000 {
|
||||
compatible = "shared-dma-pool";
|
||||
reg = <0x52800000 0x100000>;
|
||||
no-map;
|
||||
};
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
cros-ec@0 {
|
||||
compatible = "google,cros-ec-spi";
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
reg = <0>;
|
||||
cros_ec_codec: ec-codec@10500000 {
|
||||
compatible = "google,cros-ec-codec";
|
||||
#sound-dai-cells = <1>;
|
||||
reg = <0x0 0x10500000 0x80000>;
|
||||
memory-region = <&reserved_mem>;
|
||||
};
|
||||
};
|
||||
};
|
92
Documentation/devicetree/bindings/sound/ingenic,aic.yaml
Normal file
92
Documentation/devicetree/bindings/sound/ingenic,aic.yaml
Normal file
@ -0,0 +1,92 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/ingenic,aic.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Ingenic SoCs AC97 / I2S Controller (AIC) DT bindings
|
||||
|
||||
maintainers:
|
||||
- Paul Cercueil <paul@crapouillou.net>
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: '^audio-controller@'
|
||||
|
||||
compatible:
|
||||
oneOf:
|
||||
- enum:
|
||||
- ingenic,jz4740-i2s
|
||||
- ingenic,jz4760-i2s
|
||||
- ingenic,jz4770-i2s
|
||||
- ingenic,jz4780-i2s
|
||||
- items:
|
||||
- const: ingenic,jz4725b-i2s
|
||||
- const: ingenic,jz4740-i2s
|
||||
|
||||
'#sound-dai-cells':
|
||||
const: 0
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: AIC clock
|
||||
- description: I2S clock
|
||||
- description: EXT clock
|
||||
- description: PLL/2 clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: aic
|
||||
- const: i2s
|
||||
- const: ext
|
||||
- const: pll half
|
||||
|
||||
dmas:
|
||||
items:
|
||||
- description: DMA controller phandle and request line for I2S RX
|
||||
- description: DMA controller phandle and request line for I2S TX
|
||||
|
||||
dma-names:
|
||||
items:
|
||||
- const: rx
|
||||
- const: tx
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- dmas
|
||||
- dma-names
|
||||
- '#sound-dai-cells'
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/jz4740-cgu.h>
|
||||
aic: audio-controller@10020000 {
|
||||
compatible = "ingenic,jz4740-i2s";
|
||||
reg = <0x10020000 0x38>;
|
||||
|
||||
#sound-dai-cells = <0>;
|
||||
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <18>;
|
||||
|
||||
clocks = <&cgu JZ4740_CLK_AIC>,
|
||||
<&cgu JZ4740_CLK_I2S>,
|
||||
<&cgu JZ4740_CLK_EXT>,
|
||||
<&cgu JZ4740_CLK_PLL_HALF>;
|
||||
clock-names = "aic", "i2s", "ext", "pll half";
|
||||
|
||||
dmas = <&dmac 25 0xffffffff>, <&dmac 24 0xffffffff>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
@ -1,23 +0,0 @@
|
||||
Ingenic JZ4740 I2S controller
|
||||
|
||||
Required properties:
|
||||
- compatible : "ingenic,jz4740-i2s" or "ingenic,jz4780-i2s"
|
||||
- reg : I2S registers location and length
|
||||
- clocks : AIC and I2S PLL clock specifiers.
|
||||
- clock-names: "aic" and "i2s"
|
||||
- dmas: DMA controller phandle and DMA request line for I2S Tx and Rx channels
|
||||
- dma-names: Must be "tx" and "rx"
|
||||
|
||||
Example:
|
||||
|
||||
i2s: i2s@10020000 {
|
||||
compatible = "ingenic,jz4740-i2s";
|
||||
reg = <0x10020000 0x94>;
|
||||
|
||||
clocks = <&cgu JZ4740_CLK_AIC>, <&cgu JZ4740_CLK_I2SPLL>;
|
||||
clock-names = "aic", "i2s";
|
||||
|
||||
dmas = <&dma 2>, <&dma 3>;
|
||||
dma-names = "tx", "rx";
|
||||
|
||||
};
|
@ -18,6 +18,7 @@ Required properties:
|
||||
* Headphone Jack
|
||||
* Int Spk
|
||||
* Mic Jack
|
||||
* Int Mic
|
||||
|
||||
- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller
|
||||
- nvidia,audio-codec : The phandle of the WM8903 audio codec
|
||||
|
@ -10,6 +10,11 @@ Required properties:
|
||||
- clock-names: should be "pclk".
|
||||
- spk-depop-time-ms: speak depop time msec.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- mute-gpios: GPIO specifier for external line driver control (typically the
|
||||
dedicated GPIO_MUTE pin)
|
||||
|
||||
Example for rk3328 internal codec:
|
||||
|
||||
codec: codec@ff410000 {
|
||||
@ -18,6 +23,6 @@ codec: codec@ff410000 {
|
||||
rockchip,grf = <&grf>;
|
||||
clocks = <&cru PCLK_ACODEC>;
|
||||
clock-names = "pclk";
|
||||
mute-gpios = <&grf_gpio 0 GPIO_ACTIVE_LOW>;
|
||||
spk-depop-time-ms = 100;
|
||||
status = "disabled";
|
||||
};
|
||||
|
@ -1,49 +0,0 @@
|
||||
* Rockchip I2S controller
|
||||
|
||||
The I2S bus (Inter-IC sound bus) is a serial link for digital
|
||||
audio data transfer between devices in the system.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: should be one of the following:
|
||||
- "rockchip,rk3066-i2s": for rk3066
|
||||
- "rockchip,px30-i2s", "rockchip,rk3066-i2s": for px30
|
||||
- "rockchip,rk3036-i2s", "rockchip,rk3066-i2s": for rk3036
|
||||
- "rockchip,rk3188-i2s", "rockchip,rk3066-i2s": for rk3188
|
||||
- "rockchip,rk3228-i2s", "rockchip,rk3066-i2s": for rk3228
|
||||
- "rockchip,rk3288-i2s", "rockchip,rk3066-i2s": for rk3288
|
||||
- "rockchip,rk3328-i2s", "rockchip,rk3066-i2s": for rk3328
|
||||
- "rockchip,rk3366-i2s", "rockchip,rk3066-i2s": for rk3366
|
||||
- "rockchip,rk3368-i2s", "rockchip,rk3066-i2s": for rk3368
|
||||
- "rockchip,rk3399-i2s", "rockchip,rk3066-i2s": for rk3399
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- interrupts: should contain the I2S interrupt.
|
||||
- dmas: DMA specifiers for tx and rx dma. See the DMA client binding,
|
||||
Documentation/devicetree/bindings/dma/dma.txt
|
||||
- dma-names: should include "tx" and "rx".
|
||||
- clocks: a list of phandle + clock-specifer pairs, one for each entry in clock-names.
|
||||
- clock-names: should contain the following:
|
||||
- "i2s_hclk": clock for I2S BUS
|
||||
- "i2s_clk" : clock for I2S controller
|
||||
- rockchip,playback-channels: max playback channels, if not set, 8 channels default.
|
||||
- rockchip,capture-channels: max capture channels, if not set, 2 channels default.
|
||||
|
||||
Required properties for controller which support multi channels
|
||||
playback/capture:
|
||||
|
||||
- rockchip,grf: the phandle of the syscon node for GRF register.
|
||||
|
||||
Example for rk3288 I2S controller:
|
||||
|
||||
i2s@ff890000 {
|
||||
compatible = "rockchip,rk3288-i2s", "rockchip,rk3066-i2s";
|
||||
reg = <0xff890000 0x10000>;
|
||||
interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&pdma1 0>, <&pdma1 1>;
|
||||
dma-names = "tx", "rx";
|
||||
clock-names = "i2s_hclk", "i2s_clk";
|
||||
clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>;
|
||||
rockchip,playback-channels = <8>;
|
||||
rockchip,capture-channels = <2>;
|
||||
};
|
111
Documentation/devicetree/bindings/sound/rockchip-i2s.yaml
Normal file
111
Documentation/devicetree/bindings/sound/rockchip-i2s.yaml
Normal file
@ -0,0 +1,111 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/rockchip-i2s.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Rockchip I2S controller
|
||||
|
||||
description:
|
||||
The I2S bus (Inter-IC sound bus) is a serial link for digital
|
||||
audio data transfer between devices in the system.
|
||||
|
||||
maintainers:
|
||||
- Heiko Stuebner <heiko@sntech.de>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: rockchip,rk3066-i2s
|
||||
- items:
|
||||
- enum:
|
||||
- rockchip,px30-i2s
|
||||
- rockchip,rk3036-i2s
|
||||
- rockchip,rk3188-i2s
|
||||
- rockchip,rk3228-i2s
|
||||
- rockchip,rk3288-i2s
|
||||
- rockchip,rk3328-i2s
|
||||
- rockchip,rk3366-i2s
|
||||
- rockchip,rk3368-i2s
|
||||
- rockchip,rk3399-i2s
|
||||
- const: rockchip,rk3066-i2s
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: clock for I2S controller
|
||||
- description: clock for I2S BUS
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: i2s_clk
|
||||
- const: i2s_hclk
|
||||
|
||||
dmas:
|
||||
items:
|
||||
- description: TX DMA Channel
|
||||
- description: RX DMA Channel
|
||||
|
||||
dma-names:
|
||||
items:
|
||||
- const: tx
|
||||
- const: rx
|
||||
|
||||
rockchip,capture-channels:
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
default: 2
|
||||
description:
|
||||
Max capture channels, if not set, 2 channels default.
|
||||
|
||||
rockchip,playback-channels:
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
default: 8
|
||||
description:
|
||||
Max playback channels, if not set, 8 channels default.
|
||||
|
||||
rockchip,grf:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
The phandle of the syscon node for the GRF register.
|
||||
Required property for controllers which support multi channel
|
||||
playback/capture.
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- dmas
|
||||
- dma-names
|
||||
- "#sound-dai-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/rk3288-cru.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2s@ff890000 {
|
||||
compatible = "rockchip,rk3288-i2s", "rockchip,rk3066-i2s";
|
||||
reg = <0xff890000 0x10000>;
|
||||
interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru SCLK_I2S0>, <&cru HCLK_I2S0>;
|
||||
clock-names = "i2s_clk", "i2s_hclk";
|
||||
dmas = <&pdma1 0>, <&pdma1 1>;
|
||||
dma-names = "tx", "rx";
|
||||
rockchip,capture-channels = <2>;
|
||||
rockchip,playback-channels = <8>;
|
||||
#sound-dai-cells = <0>;
|
||||
};
|
@ -32,6 +32,18 @@ Optional properties:
|
||||
The delay time is realtek,btndet-delay value multiple of 8.192 ms.
|
||||
If absent, the default is 16.
|
||||
|
||||
- #clock-cells : Should be set to '<1>', wclk and bclk sources provided.
|
||||
- clock-output-names : Name given for DAI clocks output.
|
||||
|
||||
- clocks : phandle and clock specifier for codec MCLK.
|
||||
- clock-names : Clock name string for 'clocks' attribute, should be "mclk".
|
||||
|
||||
- realtek,dmic-clk-rate-hz : Set the clock rate (hz) for the requirement of
|
||||
the particular DMIC.
|
||||
|
||||
- realtek,dmic-delay-ms : Set the delay time (ms) for the requirement of
|
||||
the particular DMIC.
|
||||
|
||||
Pins on the device (for linking into audio routes) for RT5682:
|
||||
|
||||
* DMIC L1
|
||||
@ -53,4 +65,10 @@ rt5682 {
|
||||
realtek,dmic1-clk-pin = <1>;
|
||||
realtek,jd-src = <1>;
|
||||
realtek,btndet-delay = <16>;
|
||||
|
||||
#clock-cells = <1>;
|
||||
clock-output-names = "rt5682-dai-wclk", "rt5682-dai-bclk";
|
||||
|
||||
clocks = <&osc>;
|
||||
clock-names = "mclk";
|
||||
};
|
||||
|
@ -1,62 +0,0 @@
|
||||
STMicroelectronics STM32 SPI/I2S Controller
|
||||
|
||||
The SPI/I2S block supports I2S/PCM protocols when configured on I2S mode.
|
||||
Only some SPI instances support I2S.
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be "st,stm32h7-i2s"
|
||||
- reg: Offset and length of the device's register set.
|
||||
- interrupts: Must contain the interrupt line id.
|
||||
- clocks: Must contain phandle and clock specifier pairs for each entry
|
||||
in clock-names.
|
||||
- clock-names: Must contain "i2sclk", "pclk", "x8k" and "x11k".
|
||||
"i2sclk": clock which feeds the internal clock generator
|
||||
"pclk": clock which feeds the peripheral bus interface
|
||||
"x8k": I2S parent clock for sampling rates multiple of 8kHz.
|
||||
"x11k": I2S parent clock for sampling rates multiple of 11.025kHz.
|
||||
- dmas: DMA specifiers for tx and rx dma.
|
||||
See Documentation/devicetree/bindings/dma/stm32-dma.txt.
|
||||
- dma-names: Identifier for each DMA request line. Must be "tx" and "rx".
|
||||
- pinctrl-names: should contain only value "default"
|
||||
- pinctrl-0: see Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml
|
||||
|
||||
Optional properties:
|
||||
- resets: Reference to a reset controller asserting the reset controller
|
||||
|
||||
The device node should contain one 'port' child node with one child 'endpoint'
|
||||
node, according to the bindings defined in Documentation/devicetree/bindings/
|
||||
graph.txt.
|
||||
|
||||
Example:
|
||||
sound_card {
|
||||
compatible = "audio-graph-card";
|
||||
dais = <&i2s2_port>;
|
||||
};
|
||||
|
||||
i2s2: audio-controller@40003800 {
|
||||
compatible = "st,stm32h7-i2s";
|
||||
reg = <0x40003800 0x400>;
|
||||
interrupts = <36>;
|
||||
clocks = <&rcc PCLK1>, <&rcc SPI2_CK>, <&rcc PLL1_Q>, <&rcc PLL2_P>;
|
||||
clock-names = "pclk", "i2sclk", "x8k", "x11k";
|
||||
dmas = <&dmamux2 2 39 0x400 0x1>,
|
||||
<&dmamux2 3 40 0x400 0x1>;
|
||||
dma-names = "rx", "tx";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_i2s2>;
|
||||
|
||||
i2s2_port: port@0 {
|
||||
cpu_endpoint: endpoint {
|
||||
remote-endpoint = <&codec_endpoint>;
|
||||
format = "i2s";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
audio-codec {
|
||||
codec_port: port@0 {
|
||||
codec_endpoint: endpoint {
|
||||
remote-endpoint = <&cpu_endpoint>;
|
||||
};
|
||||
};
|
||||
};
|
87
Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml
Normal file
87
Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml
Normal file
@ -0,0 +1,87 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/st,stm32-i2s.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: STMicroelectronics STM32 SPI/I2S Controller
|
||||
|
||||
maintainers:
|
||||
- Olivier Moysan <olivier.moysan@st.com>
|
||||
|
||||
description:
|
||||
The SPI/I2S block supports I2S/PCM protocols when configured on I2S mode.
|
||||
Only some SPI instances support I2S.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- st,stm32h7-i2s
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: clock feeding the peripheral bus interface.
|
||||
- description: clock feeding the internal clock generator.
|
||||
- description: I2S parent clock for sampling rates multiple of 8kHz.
|
||||
- description: I2S parent clock for sampling rates multiple of 11.025kHz.
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: pclk
|
||||
- const: i2sclk
|
||||
- const: x8k
|
||||
- const: x11k
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
dmas:
|
||||
items:
|
||||
- description: audio capture DMA.
|
||||
- description: audio playback DMA.
|
||||
|
||||
dma-names:
|
||||
items:
|
||||
- const: rx
|
||||
- const: tx
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- "#sound-dai-cells"
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- interrupts
|
||||
- dmas
|
||||
- dma-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/stm32mp1-clks.h>
|
||||
i2s2: audio-controller@4000b000 {
|
||||
compatible = "st,stm32h7-i2s";
|
||||
#sound-dai-cells = <0>;
|
||||
reg = <0x4000b000 0x400>;
|
||||
clocks = <&rcc SPI2>, <&rcc SPI2_K>, <&rcc PLL3_Q>, <&rcc PLL3_R>;
|
||||
clock-names = "pclk", "i2sclk", "x8k", "x11k";
|
||||
interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&dmamux1 39 0x400 0x01>,
|
||||
<&dmamux1 40 0x400 0x01>;
|
||||
dma-names = "rx", "tx";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2s2_pins_a>;
|
||||
};
|
||||
|
||||
...
|
@ -1,56 +0,0 @@
|
||||
STMicroelectronics STM32 S/PDIF receiver (SPDIFRX).
|
||||
|
||||
The SPDIFRX peripheral, is designed to receive an S/PDIF flow compliant with
|
||||
IEC-60958 and IEC-61937.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "st,stm32h7-spdifrx"
|
||||
- reg: cpu DAI IP base address and size
|
||||
- clocks: must contain an entry for kclk (used as S/PDIF signal reference)
|
||||
- clock-names: must contain "kclk"
|
||||
- interrupts: cpu DAI interrupt line
|
||||
- dmas: DMA specifiers for audio data DMA and iec control flow DMA
|
||||
See STM32 DMA bindings, Documentation/devicetree/bindings/dma/st,stm32-dma.yaml
|
||||
- dma-names: two dmas have to be defined, "rx" and "rx-ctrl"
|
||||
|
||||
Optional properties:
|
||||
- resets: Reference to a reset controller asserting the SPDIFRX
|
||||
|
||||
The device node should contain one 'port' child node with one child 'endpoint'
|
||||
node, according to the bindings defined in Documentation/devicetree/bindings/
|
||||
graph.txt.
|
||||
|
||||
Example:
|
||||
spdifrx: spdifrx@40004000 {
|
||||
compatible = "st,stm32h7-spdifrx";
|
||||
reg = <0x40004000 0x400>;
|
||||
clocks = <&rcc SPDIFRX_CK>;
|
||||
clock-names = "kclk";
|
||||
interrupts = <97>;
|
||||
dmas = <&dmamux1 2 93 0x400 0x0>,
|
||||
<&dmamux1 3 94 0x400 0x0>;
|
||||
dma-names = "rx", "rx-ctrl";
|
||||
pinctrl-0 = <&spdifrx_pins>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
spdifrx_port: port {
|
||||
cpu_endpoint: endpoint {
|
||||
remote-endpoint = <&codec_endpoint>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
spdif_in: spdif-in {
|
||||
compatible = "linux,spdif-dir";
|
||||
|
||||
codec_port: port {
|
||||
codec_endpoint: endpoint {
|
||||
remote-endpoint = <&cpu_endpoint>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
soundcard {
|
||||
compatible = "audio-graph-card";
|
||||
dais = <&spdifrx_port>;
|
||||
};
|
@ -0,0 +1,80 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/st,stm32-spdifrx.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: STMicroelectronics STM32 S/PDIF receiver (SPDIFRX)
|
||||
|
||||
maintainers:
|
||||
- Olivier Moysan <olivier.moysan@st.com>
|
||||
|
||||
description: |
|
||||
The SPDIFRX peripheral, is designed to receive an S/PDIF flow compliant with
|
||||
IEC-60958 and IEC-61937.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- st,stm32h7-spdifrx
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: kclk
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
dmas:
|
||||
items:
|
||||
- description: audio data capture DMA
|
||||
- description: IEC status bits capture DMA
|
||||
|
||||
dma-names:
|
||||
items:
|
||||
- const: rx
|
||||
- const: rx-ctrl
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- "#sound-dai-cells"
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- interrupts
|
||||
- dmas
|
||||
- dma-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/stm32mp1-clks.h>
|
||||
spdifrx: spdifrx@40004000 {
|
||||
compatible = "st,stm32h7-spdifrx";
|
||||
#sound-dai-cells = <0>;
|
||||
reg = <0x40004000 0x400>;
|
||||
clocks = <&rcc SPDIF_K>;
|
||||
clock-names = "kclk";
|
||||
interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&dmamux1 2 93 0x400 0x0>,
|
||||
<&dmamux1 3 94 0x400 0x0>;
|
||||
dma-names = "rx", "rx-ctrl";
|
||||
pinctrl-0 = <&spdifrx_pins>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
...
|
@ -8,7 +8,7 @@ real time monitoring of loudspeaker behavior.
|
||||
Required properties:
|
||||
- #address-cells - Should be <1>.
|
||||
- #size-cells - Should be <0>.
|
||||
- compatible: - Should contain "ti,tas2562".
|
||||
- compatible: - Should contain "ti,tas2562", "ti,tas2563".
|
||||
- reg: - The i2c address. Should be 0x4c, 0x4d, 0x4e or 0x4f.
|
||||
- ti,imon-slot-no:- TDM TX current sense time slot.
|
||||
|
||||
|
82
Documentation/devicetree/bindings/sound/tlv320adcx140.yaml
Normal file
82
Documentation/devicetree/bindings/sound/tlv320adcx140.yaml
Normal file
@ -0,0 +1,82 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0+ OR BSD-2-Clause)
|
||||
# Copyright (C) 2019 Texas Instruments Incorporated
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/tlv320adcx140.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments TLV320ADCX140 Quad Channel Analog-to-Digital Converter
|
||||
|
||||
maintainers:
|
||||
- Dan Murphy <dmurphy@ti.com>
|
||||
|
||||
description: |
|
||||
The TLV320ADCX140 are multichannel (4-ch analog recording or 8-ch digital
|
||||
PDM microphones recording), high-performance audio, analog-to-digital
|
||||
converter (ADC) with analog inputs supporting up to 2V RMS. The TLV320ADCX140
|
||||
family supports line and microphone Inputs, and offers a programmable
|
||||
microphone bias or supply voltage generation.
|
||||
|
||||
Specifications can be found at:
|
||||
http://www.ti.com/lit/ds/symlink/tlv320adc3140.pdf
|
||||
http://www.ti.com/lit/ds/symlink/tlv320adc5140.pdf
|
||||
http://www.ti.com/lit/ds/symlink/tlv320adc6140.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: ti,tlv320adc3140
|
||||
- const: ti,tlv320adc5140
|
||||
- const: ti,tlv320adc6140
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
description: |
|
||||
I2C addresss of the device can be one of these 0x4c, 0x4d, 0x4e or 0x4f
|
||||
|
||||
reset-gpios:
|
||||
description: |
|
||||
GPIO used for hardware reset.
|
||||
|
||||
areg-supply:
|
||||
description: |
|
||||
Regulator with AVDD at 3.3V. If not defined then the internal regulator
|
||||
is enabled.
|
||||
|
||||
ti,mic-bias-source:
|
||||
description: |
|
||||
Indicates the source for MIC Bias.
|
||||
0 - Mic bias is set to VREF
|
||||
1 - Mic bias is set to VREF × 1.096
|
||||
6 - Mic bias is set to AVDD
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
- enum: [0, 1, 6]
|
||||
|
||||
ti,vref-source:
|
||||
description: |
|
||||
Indicates the source for MIC Bias.
|
||||
0 - Set VREF to 2.75V
|
||||
1 - Set VREF to 2.5V
|
||||
2 - Set VREF to 1.375V
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
- enum: [0, 1, 2]
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
i2c0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
codec: codec@4c {
|
||||
compatible = "ti,tlv320adc5140";
|
||||
reg = <0x4c>;
|
||||
ti,mic-bias-source = <6>;
|
||||
reset-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
@ -274,7 +274,7 @@ to know which slave triggered the interrupt.
|
||||
This is implemented the following way in the Linux kernel:
|
||||
|
||||
* I2C bus drivers which support SMBus alert should call
|
||||
i2c_setup_smbus_alert() to setup SMBus alert support.
|
||||
i2c_new_smbus_alert_device() to install SMBus alert support.
|
||||
* I2C drivers for devices which can trigger SMBus alerts should implement
|
||||
the optional alert() callback.
|
||||
|
||||
|
@ -230,7 +230,7 @@ in the used rings.
|
||||
Binary Firmware Structure
|
||||
=========================
|
||||
|
||||
At this point remoteproc only supports ELF32 firmware binaries. However,
|
||||
At this point remoteproc supports ELF32 and ELF64 firmware binaries. However,
|
||||
it is quite expected that other platforms/devices which we'd want to
|
||||
support with this framework will be based on different binary formats.
|
||||
|
||||
|
@ -2234,6 +2234,19 @@ use_vmalloc
|
||||
buffers. If mmap is used on such architectures, turn off this
|
||||
option, so that the DMA-coherent buffers are allocated and used
|
||||
instead.
|
||||
delayed_register
|
||||
The option is needed for devices that have multiple streams
|
||||
defined in multiple USB interfaces. The driver may invoke
|
||||
registrations multiple times (once per interface) and this may
|
||||
lead to the insufficient device enumeration.
|
||||
This option receives an array of strings, and you can pass
|
||||
ID:INTERFACE like ``0123abcd:4`` for performing the delayed
|
||||
registration to the given device. In this example, when a USB
|
||||
device 0123:abcd is probed, the driver waits the registration
|
||||
until the USB interface 4 gets probed.
|
||||
The driver prints a message like "Found post-registration device
|
||||
assignment: 1234abcd:04" for such a device, so that user can
|
||||
notice the need.
|
||||
|
||||
This module supports multiple devices, autoprobe and hotplugging.
|
||||
|
||||
|
@ -8,3 +8,4 @@ HD-Audio
|
||||
models
|
||||
controls
|
||||
dp-mst
|
||||
realtek-pc-beep
|
||||
|
@ -216,8 +216,6 @@ alc298-dell-aio
|
||||
ALC298 fixups on Dell AIO machines
|
||||
alc275-dell-xps
|
||||
ALC275 fixups on Dell XPS models
|
||||
alc256-dell-xps13
|
||||
ALC256 fixups on Dell XPS13
|
||||
lenovo-spk-noise
|
||||
Workaround for speaker noise on Lenovo machines
|
||||
lenovo-hotkey
|
||||
|
129
Documentation/sound/hd-audio/realtek-pc-beep.rst
Normal file
129
Documentation/sound/hd-audio/realtek-pc-beep.rst
Normal file
@ -0,0 +1,129 @@
|
||||
===============================
|
||||
Realtek PC Beep Hidden Register
|
||||
===============================
|
||||
|
||||
This file documents the "PC Beep Hidden Register", which is present in certain
|
||||
Realtek HDA codecs and controls a muxer and pair of passthrough mixers that can
|
||||
route audio between pins but aren't themselves exposed as HDA widgets. As far
|
||||
as I can tell, these hidden routes are designed to allow flexible PC Beep output
|
||||
for codecs that don't have mixer widgets in their output paths. Why it's easier
|
||||
to hide a mixer behind an undocumented vendor register than to just expose it
|
||||
as a widget, I have no idea.
|
||||
|
||||
Register Description
|
||||
====================
|
||||
|
||||
The register is accessed via processing coefficient 0x36 on NID 20h. Bits not
|
||||
identified below have no discernible effect on my machine, a Dell XPS 13 9350::
|
||||
|
||||
MSB LSB
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |h|S|L| | B |R| | Known bits
|
||||
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
|0|0|1|1| 0x7 |0|0x0|1| 0x7 | Reset value
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
1Ah input select (B): 2 bits
|
||||
When zero, expose the PC Beep line (from the internal beep generator, when
|
||||
enabled with the Set Beep Generation verb on NID 01h, or else from the
|
||||
external PCBEEP pin) on the 1Ah pin node. When nonzero, expose the headphone
|
||||
jack (or possibly Line In on some machines) input instead. If PC Beep is
|
||||
selected, the 1Ah boost control has no effect.
|
||||
|
||||
Amplify 1Ah loopback, left (L): 1 bit
|
||||
Amplify the left channel of 1Ah before mixing it into outputs as specified
|
||||
by h and S bits. Does not affect the level of 1Ah exposed to other widgets.
|
||||
|
||||
Amplify 1Ah loopback, right (R): 1 bit
|
||||
Amplify the right channel of 1Ah before mixing it into outputs as specified
|
||||
by h and S bits. Does not affect the level of 1Ah exposed to other widgets.
|
||||
|
||||
Loopback 1Ah to 21h [active low] (h): 1 bit
|
||||
When zero, mix 1Ah (possibly with amplification, depending on L and R bits)
|
||||
into 21h (headphone jack on my machine). Mixed signal respects the mute
|
||||
setting on 21h.
|
||||
|
||||
Loopback 1Ah to 14h (S): 1 bit
|
||||
When one, mix 1Ah (possibly with amplification, depending on L and R bits)
|
||||
into 14h (internal speaker on my machine). Mixed signal **ignores** the mute
|
||||
setting on 14h and is present whenever 14h is configured as an output.
|
||||
|
||||
Path diagrams
|
||||
=============
|
||||
|
||||
1Ah input selection (DIV is the PC Beep divider set on NID 01h)::
|
||||
|
||||
<Beep generator> <PCBEEP pin> <Headphone jack>
|
||||
| | |
|
||||
+--DIV--+--!DIV--+ {1Ah boost control}
|
||||
| |
|
||||
+--(b == 0)--+--(b != 0)--+
|
||||
|
|
||||
>1Ah (Beep/Headphone Mic/Line In)<
|
||||
|
||||
Loopback of 1Ah to 21h/14h::
|
||||
|
||||
<1Ah (Beep/Headphone Mic/Line In)>
|
||||
|
|
||||
{amplify if L/R}
|
||||
|
|
||||
+-----!h-----+-----S-----+
|
||||
| |
|
||||
{21h mute control} |
|
||||
| |
|
||||
>21h (Headphone)< >14h (Internal Speaker)<
|
||||
|
||||
Background
|
||||
==========
|
||||
|
||||
All Realtek HDA codecs have a vendor-defined widget with node ID 20h which
|
||||
provides access to a bank of registers that control various codec functions.
|
||||
Registers are read and written via the standard HDA processing coefficient
|
||||
verbs (Set/Get Coefficient Index, Set/Get Processing Coefficient). The node is
|
||||
named "Realtek Vendor Registers" in public datasheets' verb listings and,
|
||||
apart from that, is entirely undocumented.
|
||||
|
||||
This particular register, exposed at coefficient 0x36 and named in commits from
|
||||
Realtek, is of note: unlike most registers, which seem to control detailed
|
||||
amplifier parameters not in scope of the HDA specification, it controls audio
|
||||
routing which could just as easily have been defined using standard HDA mixer
|
||||
and selector widgets.
|
||||
|
||||
Specifically, it selects between two sources for the input pin widget with Node
|
||||
ID (NID) 1Ah: the widget's signal can come either from an audio jack (on my
|
||||
laptop, a Dell XPS 13 9350, it's the headphone jack, but comments in Realtek
|
||||
commits indicate that it might be a Line In on some machines) or from the PC
|
||||
Beep line (which is itself multiplexed between the codec's internal beep
|
||||
generator and external PCBEEP pin, depending on if the beep generator is
|
||||
enabled via verbs on NID 01h). Additionally, it can mix (with optional
|
||||
amplification) that signal onto the 21h and/or 14h output pins.
|
||||
|
||||
The register's reset value is 0x3717, corresponding to PC Beep on 1Ah that is
|
||||
then amplified and mixed into both the headphones and the speakers. Not only
|
||||
does this violate the HDA specification, which says that "[a vendor defined
|
||||
beep input pin] connection may be maintained *only* while the Link reset
|
||||
(**RST#**) is asserted", it means that we cannot ignore the register if we care
|
||||
about the input that 1Ah would otherwise expose or if the PCBEEP trace is
|
||||
poorly shielded and picks up chassis noise (both of which are the case on my
|
||||
machine).
|
||||
|
||||
Unfortunately, there are lots of ways to get this register configuration wrong.
|
||||
Linux, it seems, has gone through most of them. For one, the register resets
|
||||
after S3 suspend: judging by existing code, this isn't the case for all vendor
|
||||
registers, and it's led to some fixes that improve behavior on cold boot but
|
||||
don't last after suspend. Other fixes have successfully switched the 1Ah input
|
||||
away from PC Beep but have failed to disable both loopback paths. On my
|
||||
machine, this means that the headphone input is amplified and looped back to
|
||||
the headphone output, which uses the exact same pins! As you might expect, this
|
||||
causes terrible headphone noise, the character of which is controlled by the
|
||||
1Ah boost control. (If you've seen instructions online to fix XPS 13 headphone
|
||||
noise by changing "Headphone Mic Boost" in ALSA, now you know why.)
|
||||
|
||||
The information here has been obtained through black-box reverse engineering of
|
||||
the ALC256 codec's behavior and is not guaranteed to be correct. It likely
|
||||
also applies for the ALC255, ALC257, ALC235, and ALC236, since those codecs
|
||||
seem to be close relatives of the ALC256. (They all share one initialization
|
||||
function.) Additionally, other codecs like the ALC225 and ALC285 also have this
|
||||
register, judging by existing fixups in ``patch_realtek.c``, but specific
|
||||
data (e.g. node IDs, bit positions, pin mappings) for those codecs may differ
|
||||
from what I've described here.
|
@ -104,5 +104,10 @@ Make sure to name your corresponding cpu and codec playback and capture
|
||||
dai names ending with "Playback" and "Capture" respectively as dapm core
|
||||
will link and power those dais based on the name.
|
||||
|
||||
Note that in current device tree there is no way to mark a dai_link
|
||||
as codec to codec. However, it may change in future.
|
||||
A dai_link in a "simple-audio-card" will automatically be detected as
|
||||
codec to codec when all DAIs on the link belong to codec components.
|
||||
The dai_link will be initialized with the subset of stream parameters
|
||||
(channels, format, sample rate) supported by all DAIs on the link. Since
|
||||
there is no way to provide these parameters in the device tree, this is
|
||||
mostly useful for communication with simple fixed-function codecs, such
|
||||
as a Bluetooth controller or cellular modem.
|
||||
|
@ -1574,8 +1574,8 @@ This ioctl would set vcpu's xcr to the value userspace specified.
|
||||
};
|
||||
|
||||
#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX BIT(0)
|
||||
#define KVM_CPUID_FLAG_STATEFUL_FUNC BIT(1)
|
||||
#define KVM_CPUID_FLAG_STATE_READ_NEXT BIT(2)
|
||||
#define KVM_CPUID_FLAG_STATEFUL_FUNC BIT(1) /* deprecated */
|
||||
#define KVM_CPUID_FLAG_STATE_READ_NEXT BIT(2) /* deprecated */
|
||||
|
||||
struct kvm_cpuid_entry2 {
|
||||
__u32 function;
|
||||
@ -1626,13 +1626,6 @@ emulate them efficiently. The fields in each entry are defined as follows:
|
||||
|
||||
KVM_CPUID_FLAG_SIGNIFCANT_INDEX:
|
||||
if the index field is valid
|
||||
KVM_CPUID_FLAG_STATEFUL_FUNC:
|
||||
if cpuid for this function returns different values for successive
|
||||
invocations; there will be several entries with the same function,
|
||||
all with this flag set
|
||||
KVM_CPUID_FLAG_STATE_READ_NEXT:
|
||||
for KVM_CPUID_FLAG_STATEFUL_FUNC entries, set if this entry is
|
||||
the first entry to be read by a cpu
|
||||
|
||||
eax, ebx, ecx, edx:
|
||||
the values returned by the cpuid instruction for
|
||||
@ -2117,7 +2110,8 @@ Errors:
|
||||
|
||||
====== ============================================================
|
||||
ENOENT no such register
|
||||
EINVAL invalid register ID, or no such register
|
||||
EINVAL invalid register ID, or no such register or used with VMs in
|
||||
protected virtualization mode on s390
|
||||
EPERM (arm64) register access not allowed before vcpu finalization
|
||||
====== ============================================================
|
||||
|
||||
@ -2552,7 +2546,8 @@ Errors include:
|
||||
|
||||
======== ============================================================
|
||||
ENOENT no such register
|
||||
EINVAL invalid register ID, or no such register
|
||||
EINVAL invalid register ID, or no such register or used with VMs in
|
||||
protected virtualization mode on s390
|
||||
EPERM (arm64) register access not allowed before vcpu finalization
|
||||
======== ============================================================
|
||||
|
||||
@ -3347,8 +3342,8 @@ The member 'flags' is used for passing flags from userspace.
|
||||
::
|
||||
|
||||
#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX BIT(0)
|
||||
#define KVM_CPUID_FLAG_STATEFUL_FUNC BIT(1)
|
||||
#define KVM_CPUID_FLAG_STATE_READ_NEXT BIT(2)
|
||||
#define KVM_CPUID_FLAG_STATEFUL_FUNC BIT(1) /* deprecated */
|
||||
#define KVM_CPUID_FLAG_STATE_READ_NEXT BIT(2) /* deprecated */
|
||||
|
||||
struct kvm_cpuid_entry2 {
|
||||
__u32 function;
|
||||
@ -3394,13 +3389,6 @@ The fields in each entry are defined as follows:
|
||||
|
||||
KVM_CPUID_FLAG_SIGNIFCANT_INDEX:
|
||||
if the index field is valid
|
||||
KVM_CPUID_FLAG_STATEFUL_FUNC:
|
||||
if cpuid for this function returns different values for successive
|
||||
invocations; there will be several entries with the same function,
|
||||
all with this flag set
|
||||
KVM_CPUID_FLAG_STATE_READ_NEXT:
|
||||
for KVM_CPUID_FLAG_STATEFUL_FUNC entries, set if this entry is
|
||||
the first entry to be read by a cpu
|
||||
|
||||
eax, ebx, ecx, edx:
|
||||
|
||||
@ -4649,6 +4637,60 @@ the clear cpu reset definition in the POP. However, the cpu is not put
|
||||
into ESA mode. This reset is a superset of the initial reset.
|
||||
|
||||
|
||||
4.125 KVM_S390_PV_COMMAND
|
||||
-------------------------
|
||||
|
||||
:Capability: KVM_CAP_S390_PROTECTED
|
||||
:Architectures: s390
|
||||
:Type: vm ioctl
|
||||
:Parameters: struct kvm_pv_cmd
|
||||
:Returns: 0 on success, < 0 on error
|
||||
|
||||
::
|
||||
|
||||
struct kvm_pv_cmd {
|
||||
__u32 cmd; /* Command to be executed */
|
||||
__u16 rc; /* Ultravisor return code */
|
||||
__u16 rrc; /* Ultravisor return reason code */
|
||||
__u64 data; /* Data or address */
|
||||
__u32 flags; /* flags for future extensions. Must be 0 for now */
|
||||
__u32 reserved[3];
|
||||
};
|
||||
|
||||
cmd values:
|
||||
|
||||
KVM_PV_ENABLE
|
||||
Allocate memory and register the VM with the Ultravisor, thereby
|
||||
donating memory to the Ultravisor that will become inaccessible to
|
||||
KVM. All existing CPUs are converted to protected ones. After this
|
||||
command has succeeded, any CPU added via hotplug will become
|
||||
protected during its creation as well.
|
||||
|
||||
Errors:
|
||||
|
||||
===== =============================
|
||||
EINTR an unmasked signal is pending
|
||||
===== =============================
|
||||
|
||||
KVM_PV_DISABLE
|
||||
|
||||
Deregister the VM from the Ultravisor and reclaim the memory that
|
||||
had been donated to the Ultravisor, making it usable by the kernel
|
||||
again. All registered VCPUs are converted back to non-protected
|
||||
ones.
|
||||
|
||||
KVM_PV_VM_SET_SEC_PARMS
|
||||
Pass the image header from VM memory to the Ultravisor in
|
||||
preparation of image unpacking and verification.
|
||||
|
||||
KVM_PV_VM_UNPACK
|
||||
Unpack (protect and decrypt) a page of the encrypted boot image.
|
||||
|
||||
KVM_PV_VM_VERIFY
|
||||
Verify the integrity of the unpacked image. Only if this succeeds,
|
||||
KVM is allowed to start protected VCPUs.
|
||||
|
||||
|
||||
5. The kvm_run structure
|
||||
========================
|
||||
|
||||
@ -5707,8 +5749,13 @@ and injected exceptions.
|
||||
:Architectures: x86, arm, arm64, mips
|
||||
:Parameters: args[0] whether feature should be enabled or not
|
||||
|
||||
With this capability enabled, KVM_GET_DIRTY_LOG will not automatically
|
||||
clear and write-protect all pages that are returned as dirty.
|
||||
Valid flags are::
|
||||
|
||||
#define KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE (1 << 0)
|
||||
#define KVM_DIRTY_LOG_INITIALLY_SET (1 << 1)
|
||||
|
||||
With KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE is set, KVM_GET_DIRTY_LOG will not
|
||||
automatically clear and write-protect all pages that are returned as dirty.
|
||||
Rather, userspace will have to do this operation separately using
|
||||
KVM_CLEAR_DIRTY_LOG.
|
||||
|
||||
@ -5719,18 +5766,42 @@ than requiring to sync a full memslot; this ensures that KVM does not
|
||||
take spinlocks for an extended period of time. Second, in some cases a
|
||||
large amount of time can pass between a call to KVM_GET_DIRTY_LOG and
|
||||
userspace actually using the data in the page. Pages can be modified
|
||||
during this time, which is inefficint for both the guest and userspace:
|
||||
during this time, which is inefficient for both the guest and userspace:
|
||||
the guest will incur a higher penalty due to write protection faults,
|
||||
while userspace can see false reports of dirty pages. Manual reprotection
|
||||
helps reducing this time, improving guest performance and reducing the
|
||||
number of dirty log false positives.
|
||||
|
||||
With KVM_DIRTY_LOG_INITIALLY_SET set, all the bits of the dirty bitmap
|
||||
will be initialized to 1 when created. This also improves performance because
|
||||
dirty logging can be enabled gradually in small chunks on the first call
|
||||
to KVM_CLEAR_DIRTY_LOG. KVM_DIRTY_LOG_INITIALLY_SET depends on
|
||||
KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE (it is also only available on
|
||||
x86 for now).
|
||||
|
||||
KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 was previously available under the name
|
||||
KVM_CAP_MANUAL_DIRTY_LOG_PROTECT, but the implementation had bugs that make
|
||||
it hard or impossible to use it correctly. The availability of
|
||||
KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 signals that those bugs are fixed.
|
||||
Userspace should not try to use KVM_CAP_MANUAL_DIRTY_LOG_PROTECT.
|
||||
|
||||
7.19 KVM_CAP_PPC_SECURE_GUEST
|
||||
------------------------------
|
||||
|
||||
:Architectures: ppc
|
||||
|
||||
This capability indicates that KVM is running on a host that has
|
||||
ultravisor firmware and thus can support a secure guest. On such a
|
||||
system, a guest can ask the ultravisor to make it a secure guest,
|
||||
one whose memory is inaccessible to the host except for pages which
|
||||
are explicitly requested to be shared with the host. The ultravisor
|
||||
notifies KVM when a guest requests to become a secure guest, and KVM
|
||||
has the opportunity to veto the transition.
|
||||
|
||||
If present, this capability can be enabled for a VM, meaning that KVM
|
||||
will allow the transition to secure guest mode. Otherwise KVM will
|
||||
veto the transition.
|
||||
|
||||
8. Other capabilities.
|
||||
======================
|
||||
|
||||
@ -6027,3 +6098,14 @@ Architectures: s390
|
||||
|
||||
This capability indicates that the KVM_S390_NORMAL_RESET and
|
||||
KVM_S390_CLEAR_RESET ioctls are available.
|
||||
|
||||
8.23 KVM_CAP_S390_PROTECTED
|
||||
|
||||
Architecture: s390
|
||||
|
||||
|
||||
This capability indicates that the Ultravisor has been initialized and
|
||||
KVM can therefore start protected VMs.
|
||||
This capability governs the KVM_S390_PV_COMMAND ioctl and the
|
||||
KVM_MP_STATE_LOAD MP_STATE. KVM_SET_MP_STATE can fail for protected
|
||||
guests when the state change is invalid.
|
||||
|
@ -11,6 +11,11 @@ hypervisor when running as a guest (under Xen, KVM or any other
|
||||
hypervisor), or any hypervisor-specific interaction when the kernel is
|
||||
used as a host.
|
||||
|
||||
Note: KVM/arm has been removed from the kernel. The API described
|
||||
here is still valid though, as it allows the kernel to kexec when
|
||||
booted at HYP. It can also be used by a hypervisor other than KVM
|
||||
if necessary.
|
||||
|
||||
On arm and arm64 (without VHE), the kernel doesn't run in hypervisor
|
||||
mode, but still needs to interact with it, allowing a built-in
|
||||
hypervisor to be either installed or torn down.
|
||||
|
@ -108,16 +108,9 @@ Groups:
|
||||
mask or unmask the adapter, as specified in mask
|
||||
|
||||
KVM_S390_IO_ADAPTER_MAP
|
||||
perform a gmap translation for the guest address provided in addr,
|
||||
pin a userspace page for the translated address and add it to the
|
||||
list of mappings
|
||||
|
||||
.. note:: A new mapping will be created unconditionally; therefore,
|
||||
the calling code should avoid making duplicate mappings.
|
||||
|
||||
This is now a no-op. The mapping is purely done by the irq route.
|
||||
KVM_S390_IO_ADAPTER_UNMAP
|
||||
release a userspace page for the translated address specified in addr
|
||||
from the list of mappings
|
||||
This is now a no-op. The mapping is purely done by the irq route.
|
||||
|
||||
KVM_DEV_FLIC_AISM
|
||||
modify the adapter-interruption-suppression mode for a given isc if the
|
||||
|
@ -18,6 +18,8 @@ KVM
|
||||
nested-vmx
|
||||
ppc-pv
|
||||
s390-diag
|
||||
s390-pv
|
||||
s390-pv-boot
|
||||
timekeeping
|
||||
vcpu-requests
|
||||
|
||||
|
@ -96,19 +96,18 @@ will happen:
|
||||
We dirty-log for gfn1, that means gfn2 is lost in dirty-bitmap.
|
||||
|
||||
For direct sp, we can easily avoid it since the spte of direct sp is fixed
|
||||
to gfn. For indirect sp, before we do cmpxchg, we call gfn_to_pfn_atomic()
|
||||
to pin gfn to pfn, because after gfn_to_pfn_atomic():
|
||||
to gfn. For indirect sp, we disabled fast page fault for simplicity.
|
||||
|
||||
A solution for indirect sp could be to pin the gfn, for example via
|
||||
kvm_vcpu_gfn_to_pfn_atomic, before the cmpxchg. After the pinning:
|
||||
|
||||
- We have held the refcount of pfn that means the pfn can not be freed and
|
||||
be reused for another gfn.
|
||||
- The pfn is writable that means it can not be shared between different gfns
|
||||
- The pfn is writable and therefore it cannot be shared between different gfns
|
||||
by KSM.
|
||||
|
||||
Then, we can ensure the dirty bitmaps is correctly set for a gfn.
|
||||
|
||||
Currently, to simplify the whole things, we disable fast page fault for
|
||||
indirect shadow page.
|
||||
|
||||
2) Dirty bit tracking
|
||||
|
||||
In the origin code, the spte can be fast updated (non-atomically) if the
|
||||
|
84
Documentation/virt/kvm/s390-pv-boot.rst
Normal file
84
Documentation/virt/kvm/s390-pv-boot.rst
Normal file
@ -0,0 +1,84 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
======================================
|
||||
s390 (IBM Z) Boot/IPL of Protected VMs
|
||||
======================================
|
||||
|
||||
Summary
|
||||
-------
|
||||
The memory of Protected Virtual Machines (PVMs) is not accessible to
|
||||
I/O or the hypervisor. In those cases where the hypervisor needs to
|
||||
access the memory of a PVM, that memory must be made accessible.
|
||||
Memory made accessible to the hypervisor will be encrypted. See
|
||||
:doc:`s390-pv` for details."
|
||||
|
||||
On IPL (boot) a small plaintext bootloader is started, which provides
|
||||
information about the encrypted components and necessary metadata to
|
||||
KVM to decrypt the protected virtual machine.
|
||||
|
||||
Based on this data, KVM will make the protected virtual machine known
|
||||
to the Ultravisor (UV) and instruct it to secure the memory of the
|
||||
PVM, decrypt the components and verify the data and address list
|
||||
hashes, to ensure integrity. Afterwards KVM can run the PVM via the
|
||||
SIE instruction which the UV will intercept and execute on KVM's
|
||||
behalf.
|
||||
|
||||
As the guest image is just like an opaque kernel image that does the
|
||||
switch into PV mode itself, the user can load encrypted guest
|
||||
executables and data via every available method (network, dasd, scsi,
|
||||
direct kernel, ...) without the need to change the boot process.
|
||||
|
||||
|
||||
Diag308
|
||||
-------
|
||||
This diagnose instruction is the basic mechanism to handle IPL and
|
||||
related operations for virtual machines. The VM can set and retrieve
|
||||
IPL information blocks, that specify the IPL method/devices and
|
||||
request VM memory and subsystem resets, as well as IPLs.
|
||||
|
||||
For PVMs this concept has been extended with new subcodes:
|
||||
|
||||
Subcode 8: Set an IPL Information Block of type 5 (information block
|
||||
for PVMs)
|
||||
Subcode 9: Store the saved block in guest memory
|
||||
Subcode 10: Move into Protected Virtualization mode
|
||||
|
||||
The new PV load-device-specific-parameters field specifies all data
|
||||
that is necessary to move into PV mode.
|
||||
|
||||
* PV Header origin
|
||||
* PV Header length
|
||||
* List of Components composed of
|
||||
* AES-XTS Tweak prefix
|
||||
* Origin
|
||||
* Size
|
||||
|
||||
The PV header contains the keys and hashes, which the UV will use to
|
||||
decrypt and verify the PV, as well as control flags and a start PSW.
|
||||
|
||||
The components are for instance an encrypted kernel, kernel parameters
|
||||
and initrd. The components are decrypted by the UV.
|
||||
|
||||
After the initial import of the encrypted data, all defined pages will
|
||||
contain the guest content. All non-specified pages will start out as
|
||||
zero pages on first access.
|
||||
|
||||
|
||||
When running in protected virtualization mode, some subcodes will result in
|
||||
exceptions or return error codes.
|
||||
|
||||
Subcodes 4 and 7, which specify operations that do not clear the guest
|
||||
memory, will result in specification exceptions. This is because the
|
||||
UV will clear all memory when a secure VM is removed, and therefore
|
||||
non-clearing IPL subcodes are not allowed.
|
||||
|
||||
Subcodes 8, 9, 10 will result in specification exceptions.
|
||||
Re-IPL into a protected mode is only possible via a detour into non
|
||||
protected mode.
|
||||
|
||||
Keys
|
||||
----
|
||||
Every CEC will have a unique public key to enable tooling to build
|
||||
encrypted images.
|
||||
See `s390-tools <https://github.com/ibm-s390-tools/s390-tools/>`_
|
||||
for the tooling.
|
116
Documentation/virt/kvm/s390-pv.rst
Normal file
116
Documentation/virt/kvm/s390-pv.rst
Normal file
@ -0,0 +1,116 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=========================================
|
||||
s390 (IBM Z) Ultravisor and Protected VMs
|
||||
=========================================
|
||||
|
||||
Summary
|
||||
-------
|
||||
Protected virtual machines (PVM) are KVM VMs that do not allow KVM to
|
||||
access VM state like guest memory or guest registers. Instead, the
|
||||
PVMs are mostly managed by a new entity called Ultravisor (UV). The UV
|
||||
provides an API that can be used by PVMs and KVM to request management
|
||||
actions.
|
||||
|
||||
Each guest starts in non-protected mode and then may make a request to
|
||||
transition into protected mode. On transition, KVM registers the guest
|
||||
and its VCPUs with the Ultravisor and prepares everything for running
|
||||
it.
|
||||
|
||||
The Ultravisor will secure and decrypt the guest's boot memory
|
||||
(i.e. kernel/initrd). It will safeguard state changes like VCPU
|
||||
starts/stops and injected interrupts while the guest is running.
|
||||
|
||||
As access to the guest's state, such as the SIE state description, is
|
||||
normally needed to be able to run a VM, some changes have been made in
|
||||
the behavior of the SIE instruction. A new format 4 state description
|
||||
has been introduced, where some fields have different meanings for a
|
||||
PVM. SIE exits are minimized as much as possible to improve speed and
|
||||
reduce exposed guest state.
|
||||
|
||||
|
||||
Interrupt injection
|
||||
-------------------
|
||||
Interrupt injection is safeguarded by the Ultravisor. As KVM doesn't
|
||||
have access to the VCPUs' lowcores, injection is handled via the
|
||||
format 4 state description.
|
||||
|
||||
Machine check, external, IO and restart interruptions each can be
|
||||
injected on SIE entry via a bit in the interrupt injection control
|
||||
field (offset 0x54). If the guest cpu is not enabled for the interrupt
|
||||
at the time of injection, a validity interception is recognized. The
|
||||
format 4 state description contains fields in the interception data
|
||||
block where data associated with the interrupt can be transported.
|
||||
|
||||
Program and Service Call exceptions have another layer of
|
||||
safeguarding; they can only be injected for instructions that have
|
||||
been intercepted into KVM. The exceptions need to be a valid outcome
|
||||
of an instruction emulation by KVM, e.g. we can never inject a
|
||||
addressing exception as they are reported by SIE since KVM has no
|
||||
access to the guest memory.
|
||||
|
||||
|
||||
Mask notification interceptions
|
||||
-------------------------------
|
||||
KVM cannot intercept lctl(g) and lpsw(e) anymore in order to be
|
||||
notified when a PVM enables a certain class of interrupt. As a
|
||||
replacement, two new interception codes have been introduced: One
|
||||
indicating that the contents of CRs 0, 6, or 14 have been changed,
|
||||
indicating different interruption subclasses; and one indicating that
|
||||
PSW bit 13 has been changed, indicating that a machine check
|
||||
intervention was requested and those are now enabled.
|
||||
|
||||
Instruction emulation
|
||||
---------------------
|
||||
With the format 4 state description for PVMs, the SIE instruction already
|
||||
interprets more instructions than it does with format 2. It is not able
|
||||
to interpret every instruction, but needs to hand some tasks to KVM;
|
||||
therefore, the SIE and the ultravisor safeguard emulation inputs and outputs.
|
||||
|
||||
The control structures associated with SIE provide the Secure
|
||||
Instruction Data Area (SIDA), the Interception Parameters (IP) and the
|
||||
Secure Interception General Register Save Area. Guest GRs and most of
|
||||
the instruction data, such as I/O data structures, are filtered.
|
||||
Instruction data is copied to and from the SIDA when needed. Guest
|
||||
GRs are put into / retrieved from the Secure Interception General
|
||||
Register Save Area.
|
||||
|
||||
Only GR values needed to emulate an instruction will be copied into this
|
||||
save area and the real register numbers will be hidden.
|
||||
|
||||
The Interception Parameters state description field still contains the
|
||||
the bytes of the instruction text, but with pre-set register values
|
||||
instead of the actual ones. I.e. each instruction always uses the same
|
||||
instruction text, in order not to leak guest instruction text.
|
||||
This also implies that the register content that a guest had in r<n>
|
||||
may be in r<m> from the hypervisor's point of view.
|
||||
|
||||
The Secure Instruction Data Area contains instruction storage
|
||||
data. Instruction data, i.e. data being referenced by an instruction
|
||||
like the SCCB for sclp, is moved via the SIDA. When an instruction is
|
||||
intercepted, the SIE will only allow data and program interrupts for
|
||||
this instruction to be moved to the guest via the two data areas
|
||||
discussed before. Other data is either ignored or results in validity
|
||||
interceptions.
|
||||
|
||||
|
||||
Instruction emulation interceptions
|
||||
-----------------------------------
|
||||
There are two types of SIE secure instruction intercepts: the normal
|
||||
and the notification type. Normal secure instruction intercepts will
|
||||
make the guest pending for instruction completion of the intercepted
|
||||
instruction type, i.e. on SIE entry it is attempted to complete
|
||||
emulation of the instruction with the data provided by KVM. That might
|
||||
be a program exception or instruction completion.
|
||||
|
||||
The notification type intercepts inform KVM about guest environment
|
||||
changes due to guest instruction interpretation. Such an interception
|
||||
is recognized, for example, for the store prefix instruction to provide
|
||||
the new lowcore location. On SIE reentry, any KVM data in the data areas
|
||||
is ignored and execution continues as if the guest instruction had
|
||||
completed. For that reason KVM is not allowed to inject a program
|
||||
interrupt.
|
||||
|
||||
Links
|
||||
-----
|
||||
`KVM Forum 2019 presentation <https://static.sched.com/hosted_files/kvmforum2019/3b/ibm_protected_vms_s390x.pdf>`_
|
68
MAINTAINERS
68
MAINTAINERS
@ -1945,7 +1945,7 @@ F: Documentation/devicetree/bindings/i2c/i2c-lpc2k.txt
|
||||
F: arch/arm/boot/dts/lpc43*
|
||||
F: drivers/i2c/busses/i2c-lpc2k.c
|
||||
F: drivers/memory/pl172.c
|
||||
F: drivers/mtd/spi-nor/nxp-spifi.c
|
||||
F: drivers/mtd/spi-nor/controllers/nxp-spifi.c
|
||||
F: drivers/rtc/rtc-lpc24xx.c
|
||||
N: lpc18xx
|
||||
|
||||
@ -2743,8 +2743,8 @@ L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
|
||||
L: openbmc@lists.ozlabs.org (moderated for non-subscribers)
|
||||
L: linux-gpio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/pinctrl/aspeed/
|
||||
F: Documentation/devicetree/bindings/pinctrl/aspeed,*
|
||||
F: drivers/pinctrl/aspeed/
|
||||
|
||||
ASPEED SCU INTERRUPT CONTROLLER DRIVER
|
||||
M: Eddie James <eajames@linux.ibm.com>
|
||||
@ -3470,7 +3470,7 @@ L: linux-i2c@vger.kernel.org
|
||||
L: bcm-kernel-feedback-list@broadcom.com
|
||||
S: Supported
|
||||
F: drivers/i2c/busses/i2c-brcmstb.c
|
||||
F: Documentation/devicetree/bindings/i2c/i2c-brcmstb.txt
|
||||
F: Documentation/devicetree/bindings/i2c/brcm,brcmstb-i2c.yaml
|
||||
|
||||
BROADCOM BRCMSTB USB2 and USB3 PHY DRIVER
|
||||
M: Al Cooper <alcooperx@gmail.com>
|
||||
@ -4055,8 +4055,8 @@ F: Documentation/devicetree/bindings/sound/google,cros-ec-codec.yaml
|
||||
F: sound/soc/codecs/cros_ec_codec.*
|
||||
|
||||
CIRRUS LOGIC AUDIO CODEC DRIVERS
|
||||
M: Brian Austin <brian.austin@cirrus.com>
|
||||
M: Paul Handrigan <Paul.Handrigan@cirrus.com>
|
||||
M: James Schulman <james.schulman@cirrus.com>
|
||||
M: David Rhodes <david.rhodes@cirrus.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: sound/soc/codecs/cs*
|
||||
@ -4958,6 +4958,7 @@ F: drivers/leds/leds-da90??.c
|
||||
F: drivers/mfd/da903x.c
|
||||
F: drivers/mfd/da90??-*.c
|
||||
F: drivers/mfd/da91??-*.c
|
||||
F: drivers/pinctrl/pinctrl-da90??.c
|
||||
F: drivers/power/supply/da9052-battery.c
|
||||
F: drivers/power/supply/da91??-*.c
|
||||
F: drivers/regulator/da903x.c
|
||||
@ -7850,6 +7851,10 @@ F: Documentation/ABI/testing/debugfs-hyperv
|
||||
|
||||
HYPERBUS SUPPORT
|
||||
M: Vignesh Raghavendra <vigneshr@ti.com>
|
||||
L: linux-mtd@lists.infradead.org
|
||||
Q: http://patchwork.ozlabs.org/project/linux-mtd/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git cfi/next
|
||||
C: irc://irc.oftc.net/mtd
|
||||
S: Supported
|
||||
F: drivers/mtd/hyperbus/
|
||||
F: include/linux/mtd/hyperbus.h
|
||||
@ -9244,7 +9249,7 @@ F: virt/kvm/*
|
||||
F: tools/kvm/
|
||||
F: tools/testing/selftests/kvm/
|
||||
|
||||
KERNEL VIRTUAL MACHINE FOR ARM/ARM64 (KVM/arm, KVM/arm64)
|
||||
KERNEL VIRTUAL MACHINE FOR ARM64 (KVM/arm64)
|
||||
M: Marc Zyngier <maz@kernel.org>
|
||||
R: James Morse <james.morse@arm.com>
|
||||
R: Julien Thierry <julien.thierry.kdev@gmail.com>
|
||||
@ -9253,9 +9258,6 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
L: kvmarm@lists.cs.columbia.edu
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git
|
||||
S: Maintained
|
||||
F: arch/arm/include/uapi/asm/kvm*
|
||||
F: arch/arm/include/asm/kvm*
|
||||
F: arch/arm/kvm/
|
||||
F: arch/arm64/include/uapi/asm/kvm*
|
||||
F: arch/arm64/include/asm/kvm*
|
||||
F: arch/arm64/kvm/
|
||||
@ -9290,6 +9292,7 @@ L: kvm@vger.kernel.org
|
||||
W: http://www.ibm.com/developerworks/linux/linux390/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git
|
||||
S: Supported
|
||||
F: Documentation/virt/kvm/s390*
|
||||
F: arch/s390/include/uapi/asm/kvm*
|
||||
F: arch/s390/include/asm/gmap.h
|
||||
F: arch/s390/include/asm/kvm*
|
||||
@ -11553,6 +11556,7 @@ L: linux-mtd@lists.infradead.org
|
||||
W: http://www.linux-mtd.infradead.org/
|
||||
Q: http://patchwork.ozlabs.org/project/linux-mtd/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git nand/next
|
||||
C: irc://irc.oftc.net/mtd
|
||||
S: Maintained
|
||||
F: drivers/mtd/nand/
|
||||
F: include/linux/mtd/*nand*.h
|
||||
@ -13275,21 +13279,13 @@ K: \b(clone_args|kernel_clone_args)\b
|
||||
PIN CONTROL SUBSYSTEM
|
||||
M: Linus Walleij <linus.walleij@linaro.org>
|
||||
L: linux-gpio@vger.kernel.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git
|
||||
F: Documentation/devicetree/bindings/pinctrl/
|
||||
F: Documentation/driver-api/pinctl.rst
|
||||
F: drivers/pinctrl/
|
||||
F: include/linux/pinctrl/
|
||||
|
||||
PIN CONTROLLER - MICROCHIP AT91
|
||||
M: Ludovic Desroches <ludovic.desroches@microchip.com>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
L: linux-gpio@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/pinctrl/pinctrl-at91*
|
||||
F: drivers/gpio/gpio-sama5d2-piobu.c
|
||||
|
||||
PIN CONTROLLER - FREESCALE
|
||||
M: Dong Aisheng <aisheng.dong@nxp.com>
|
||||
M: Fabio Estevam <festevam@gmail.com>
|
||||
@ -13298,14 +13294,14 @@ M: Stefan Agner <stefan@agner.ch>
|
||||
R: Pengutronix Kernel Team <kernel@pengutronix.de>
|
||||
L: linux-gpio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/pinctrl/freescale/
|
||||
F: Documentation/devicetree/bindings/pinctrl/fsl,*
|
||||
F: drivers/pinctrl/freescale/
|
||||
|
||||
PIN CONTROLLER - INTEL
|
||||
M: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
M: Andy Shevchenko <andy@kernel.org>
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/intel.git
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/intel.git
|
||||
F: drivers/pinctrl/intel/
|
||||
|
||||
PIN CONTROLLER - MEDIATEK
|
||||
@ -13316,18 +13312,26 @@ F: Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
|
||||
F: Documentation/devicetree/bindings/pinctrl/pinctrl-mt7622.txt
|
||||
F: drivers/pinctrl/mediatek/
|
||||
|
||||
PIN CONTROLLER - MICROCHIP AT91
|
||||
M: Ludovic Desroches <ludovic.desroches@microchip.com>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
L: linux-gpio@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/gpio/gpio-sama5d2-piobu.c
|
||||
F: drivers/pinctrl/pinctrl-at91*
|
||||
|
||||
PIN CONTROLLER - QUALCOMM
|
||||
M: Bjorn Andersson <bjorn.andersson@linaro.org>
|
||||
S: Maintained
|
||||
L: linux-arm-msm@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/pinctrl/qcom,*.txt
|
||||
F: drivers/pinctrl/qcom/
|
||||
|
||||
PIN CONTROLLER - RENESAS
|
||||
M: Geert Uytterhoeven <geert+renesas@glider.be>
|
||||
L: linux-renesas-soc@vger.kernel.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git sh-pfc
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git sh-pfc
|
||||
F: drivers/pinctrl/pinctrl-rz*
|
||||
F: drivers/pinctrl/sh-pfc/
|
||||
|
||||
@ -13337,12 +13341,12 @@ M: Krzysztof Kozlowski <krzk@kernel.org>
|
||||
M: Sylwester Nawrocki <s.nawrocki@samsung.com>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
|
||||
Q: https://patchwork.kernel.org/project/linux-samsung-soc/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/samsung.git
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/samsung.git
|
||||
Q: https://patchwork.kernel.org/project/linux-samsung-soc/list/
|
||||
F: Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
|
||||
F: drivers/pinctrl/samsung/
|
||||
F: include/dt-bindings/pinctrl/samsung.h
|
||||
F: Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
|
||||
|
||||
PIN CONTROLLER - SINGLE
|
||||
M: Tony Lindgren <tony@atomide.com>
|
||||
@ -13355,8 +13359,8 @@ F: drivers/pinctrl/pinctrl-single.c
|
||||
PIN CONTROLLER - ST SPEAR
|
||||
M: Viresh Kumar <vireshk@kernel.org>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
W: http://www.st.com/spear
|
||||
S: Maintained
|
||||
W: http://www.st.com/spear
|
||||
F: drivers/pinctrl/spear/
|
||||
|
||||
PISTACHIO SOC SUPPORT
|
||||
@ -15757,6 +15761,17 @@ F: sound/soc/
|
||||
F: include/dt-bindings/sound/
|
||||
F: include/sound/soc*
|
||||
|
||||
SOUND - SOUND OPEN FIRMWARE (SOF) DRIVERS
|
||||
M: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
M: Liam Girdwood <lgirdwood@gmail.com>
|
||||
M: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
|
||||
M: Kai Vehmanen <kai.vehmanen@linux.intel.com>
|
||||
M: Daniel Baluta <daniel.baluta@nxp.com>
|
||||
L: sound-open-firmware@alsa-project.org (moderated for non-subscribers)
|
||||
W: https://github.com/thesofproject/linux/
|
||||
S: Supported
|
||||
F: sound/soc/sof/
|
||||
|
||||
SOUNDWIRE SUBSYSTEM
|
||||
M: Vinod Koul <vkoul@kernel.org>
|
||||
M: Sanyog Kale <sanyog.r.kale@intel.com>
|
||||
@ -15831,6 +15846,7 @@ L: linux-mtd@lists.infradead.org
|
||||
W: http://www.linux-mtd.infradead.org/
|
||||
Q: http://patchwork.ozlabs.org/project/linux-mtd/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git spi-nor/next
|
||||
C: irc://irc.oftc.net/mtd
|
||||
S: Maintained
|
||||
F: drivers/mtd/spi-nor/
|
||||
F: include/linux/mtd/spi-nor.h
|
||||
|
@ -1,17 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
generated-y += syscall_table.h
|
||||
generic-y += compat.h
|
||||
generic-y += exec.h
|
||||
generic-y += export.h
|
||||
generic-y += fb.h
|
||||
generic-y += irq_work.h
|
||||
generic-y += kvm_para.h
|
||||
generic-y += mcs_spinlock.h
|
||||
generic-y += mm-arch-hooks.h
|
||||
generic-y += mmiowb.h
|
||||
generic-y += preempt.h
|
||||
generic-y += sections.h
|
||||
generic-y += trace_clock.h
|
||||
generic-y += current.h
|
||||
generic-y += kprobes.h
|
||||
|
@ -89,7 +89,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
|
||||
const struct exception_table_entry *fixup;
|
||||
int si_code = SEGV_MAPERR;
|
||||
vm_fault_t fault;
|
||||
unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
|
||||
unsigned int flags = FAULT_FLAG_DEFAULT;
|
||||
|
||||
/* As of EV6, a load into $31/$f31 is a prefetch, and never faults
|
||||
(or is suppressed by the PALcode). Support that for older CPUs
|
||||
@ -150,7 +150,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
|
||||
the fault. */
|
||||
fault = handle_mm_fault(vma, address, flags);
|
||||
|
||||
if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
|
||||
if (fault_signal_pending(fault, regs))
|
||||
return;
|
||||
|
||||
if (unlikely(fault & VM_FAULT_ERROR)) {
|
||||
@ -169,7 +169,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
|
||||
else
|
||||
current->min_flt++;
|
||||
if (fault & VM_FAULT_RETRY) {
|
||||
flags &= ~FAULT_FLAG_ALLOW_RETRY;
|
||||
flags |= FAULT_FLAG_TRIED;
|
||||
|
||||
/* No need to up_read(&mm->mmap_sem) as we would
|
||||
* have already released it in __lock_page_or_retry
|
||||
|
@ -1,28 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
generic-y += bugs.h
|
||||
generic-y += compat.h
|
||||
generic-y += device.h
|
||||
generic-y += div64.h
|
||||
generic-y += dma-mapping.h
|
||||
generic-y += emergency-restart.h
|
||||
generic-y += extable.h
|
||||
generic-y += ftrace.h
|
||||
generic-y += hardirq.h
|
||||
generic-y += hw_irq.h
|
||||
generic-y += irq_regs.h
|
||||
generic-y += irq_work.h
|
||||
generic-y += kvm_para.h
|
||||
generic-y += local.h
|
||||
generic-y += local64.h
|
||||
generic-y += mcs_spinlock.h
|
||||
generic-y += mm-arch-hooks.h
|
||||
generic-y += mmiowb.h
|
||||
generic-y += parport.h
|
||||
generic-y += percpu.h
|
||||
generic-y += preempt.h
|
||||
generic-y += topology.h
|
||||
generic-y += trace_clock.h
|
||||
generic-y += user.h
|
||||
generic-y += vga.h
|
||||
generic-y += word-at-a-time.h
|
||||
generic-y += xor.h
|
||||
|
@ -100,7 +100,7 @@ void do_page_fault(unsigned long address, struct pt_regs *regs)
|
||||
(regs->ecr_cause == ECR_C_PROTV_INST_FETCH))
|
||||
exec = 1;
|
||||
|
||||
flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
|
||||
flags = FAULT_FLAG_DEFAULT;
|
||||
if (user_mode(regs))
|
||||
flags |= FAULT_FLAG_USER;
|
||||
if (write)
|
||||
@ -133,29 +133,20 @@ void do_page_fault(unsigned long address, struct pt_regs *regs)
|
||||
|
||||
fault = handle_mm_fault(vma, address, flags);
|
||||
|
||||
/*
|
||||
* Fault retry nuances
|
||||
*/
|
||||
if (unlikely(fault & VM_FAULT_RETRY)) {
|
||||
/* Quick path to respond to signals */
|
||||
if (fault_signal_pending(fault, regs)) {
|
||||
if (!user_mode(regs))
|
||||
goto no_context;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If fault needs to be retried, handle any pending signals
|
||||
* first (by returning to user mode).
|
||||
* mmap_sem already relinquished by core mm for RETRY case
|
||||
*/
|
||||
if (fatal_signal_pending(current)) {
|
||||
if (!user_mode(regs))
|
||||
goto no_context;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* retry state machine
|
||||
*/
|
||||
if (flags & FAULT_FLAG_ALLOW_RETRY) {
|
||||
flags &= ~FAULT_FLAG_ALLOW_RETRY;
|
||||
flags |= FAULT_FLAG_TRIED;
|
||||
goto retry;
|
||||
}
|
||||
/*
|
||||
* Fault retry nuances, mmap_sem already relinquished by core mm
|
||||
*/
|
||||
if (unlikely((fault & VM_FAULT_RETRY) &&
|
||||
(flags & FAULT_FLAG_ALLOW_RETRY))) {
|
||||
flags |= FAULT_FLAG_TRIED;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
bad_area:
|
||||
|
@ -2090,5 +2090,3 @@ source "drivers/firmware/Kconfig"
|
||||
if CRYPTO
|
||||
source "arch/arm/crypto/Kconfig"
|
||||
endif
|
||||
|
||||
source "arch/arm/kvm/Kconfig"
|
||||
|
@ -278,7 +278,6 @@ core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/
|
||||
core-$(CONFIG_FPE_FASTFPE) += $(patsubst $(srctree)/%,%,$(wildcard $(srctree)/arch/arm/fastfpe/))
|
||||
core-$(CONFIG_VFP) += arch/arm/vfp/
|
||||
core-$(CONFIG_XEN) += arch/arm/xen/
|
||||
core-$(CONFIG_KVM_ARM_HOST) += arch/arm/kvm/
|
||||
core-$(CONFIG_VDSO) += arch/arm/vdso/
|
||||
|
||||
# If we have a machine-specific directory, then include it in the build.
|
||||
|
@ -236,5 +236,3 @@ CONFIG_CRYPTO_GCM=y
|
||||
CONFIG_CRYPTO_XCBC=y
|
||||
CONFIG_CRYPTO_SHA256=y
|
||||
# CONFIG_CRYPTO_ANSI_CPRNG is not set
|
||||
CONFIG_VIRTUALIZATION=y
|
||||
CONFIG_KVM=y
|
||||
|
@ -1,22 +1,10 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
generic-y += compat.h
|
||||
generic-y += current.h
|
||||
generic-y += early_ioremap.h
|
||||
generic-y += emergency-restart.h
|
||||
generic-y += exec.h
|
||||
generic-y += extable.h
|
||||
generic-y += flat.h
|
||||
generic-y += irq_regs.h
|
||||
generic-y += kdebug.h
|
||||
generic-y += local.h
|
||||
generic-y += local64.h
|
||||
generic-y += mm-arch-hooks.h
|
||||
generic-y += mmiowb.h
|
||||
generic-y += parport.h
|
||||
generic-y += preempt.h
|
||||
generic-y += seccomp.h
|
||||
generic-y += serial.h
|
||||
generic-y += trace_clock.h
|
||||
|
||||
generated-y += mach-types.h
|
||||
generated-y += unistd-nr.h
|
||||
|
@ -38,71 +38,6 @@
|
||||
#define ICC_AP1R2 __ICC_AP1Rx(2)
|
||||
#define ICC_AP1R3 __ICC_AP1Rx(3)
|
||||
|
||||
#define ICC_HSRE __ACCESS_CP15(c12, 4, c9, 5)
|
||||
|
||||
#define ICH_VSEIR __ACCESS_CP15(c12, 4, c9, 4)
|
||||
#define ICH_HCR __ACCESS_CP15(c12, 4, c11, 0)
|
||||
#define ICH_VTR __ACCESS_CP15(c12, 4, c11, 1)
|
||||
#define ICH_MISR __ACCESS_CP15(c12, 4, c11, 2)
|
||||
#define ICH_EISR __ACCESS_CP15(c12, 4, c11, 3)
|
||||
#define ICH_ELRSR __ACCESS_CP15(c12, 4, c11, 5)
|
||||
#define ICH_VMCR __ACCESS_CP15(c12, 4, c11, 7)
|
||||
|
||||
#define __LR0(x) __ACCESS_CP15(c12, 4, c12, x)
|
||||
#define __LR8(x) __ACCESS_CP15(c12, 4, c13, x)
|
||||
|
||||
#define ICH_LR0 __LR0(0)
|
||||
#define ICH_LR1 __LR0(1)
|
||||
#define ICH_LR2 __LR0(2)
|
||||
#define ICH_LR3 __LR0(3)
|
||||
#define ICH_LR4 __LR0(4)
|
||||
#define ICH_LR5 __LR0(5)
|
||||
#define ICH_LR6 __LR0(6)
|
||||
#define ICH_LR7 __LR0(7)
|
||||
#define ICH_LR8 __LR8(0)
|
||||
#define ICH_LR9 __LR8(1)
|
||||
#define ICH_LR10 __LR8(2)
|
||||
#define ICH_LR11 __LR8(3)
|
||||
#define ICH_LR12 __LR8(4)
|
||||
#define ICH_LR13 __LR8(5)
|
||||
#define ICH_LR14 __LR8(6)
|
||||
#define ICH_LR15 __LR8(7)
|
||||
|
||||
/* LR top half */
|
||||
#define __LRC0(x) __ACCESS_CP15(c12, 4, c14, x)
|
||||
#define __LRC8(x) __ACCESS_CP15(c12, 4, c15, x)
|
||||
|
||||
#define ICH_LRC0 __LRC0(0)
|
||||
#define ICH_LRC1 __LRC0(1)
|
||||
#define ICH_LRC2 __LRC0(2)
|
||||
#define ICH_LRC3 __LRC0(3)
|
||||
#define ICH_LRC4 __LRC0(4)
|
||||
#define ICH_LRC5 __LRC0(5)
|
||||
#define ICH_LRC6 __LRC0(6)
|
||||
#define ICH_LRC7 __LRC0(7)
|
||||
#define ICH_LRC8 __LRC8(0)
|
||||
#define ICH_LRC9 __LRC8(1)
|
||||
#define ICH_LRC10 __LRC8(2)
|
||||
#define ICH_LRC11 __LRC8(3)
|
||||
#define ICH_LRC12 __LRC8(4)
|
||||
#define ICH_LRC13 __LRC8(5)
|
||||
#define ICH_LRC14 __LRC8(6)
|
||||
#define ICH_LRC15 __LRC8(7)
|
||||
|
||||
#define __ICH_AP0Rx(x) __ACCESS_CP15(c12, 4, c8, x)
|
||||
#define ICH_AP0R0 __ICH_AP0Rx(0)
|
||||
#define ICH_AP0R1 __ICH_AP0Rx(1)
|
||||
#define ICH_AP0R2 __ICH_AP0Rx(2)
|
||||
#define ICH_AP0R3 __ICH_AP0Rx(3)
|
||||
|
||||
#define __ICH_AP1Rx(x) __ACCESS_CP15(c12, 4, c9, x)
|
||||
#define ICH_AP1R0 __ICH_AP1Rx(0)
|
||||
#define ICH_AP1R1 __ICH_AP1Rx(1)
|
||||
#define ICH_AP1R2 __ICH_AP1Rx(2)
|
||||
#define ICH_AP1R3 __ICH_AP1Rx(3)
|
||||
|
||||
/* A32-to-A64 mappings used by VGIC save/restore */
|
||||
|
||||
#define CPUIF_MAP(a32, a64) \
|
||||
static inline void write_ ## a64(u32 val) \
|
||||
{ \
|
||||
@ -113,21 +48,6 @@ static inline u32 read_ ## a64(void) \
|
||||
return read_sysreg(a32); \
|
||||
} \
|
||||
|
||||
#define CPUIF_MAP_LO_HI(a32lo, a32hi, a64) \
|
||||
static inline void write_ ## a64(u64 val) \
|
||||
{ \
|
||||
write_sysreg(lower_32_bits(val), a32lo);\
|
||||
write_sysreg(upper_32_bits(val), a32hi);\
|
||||
} \
|
||||
static inline u64 read_ ## a64(void) \
|
||||
{ \
|
||||
u64 val = read_sysreg(a32lo); \
|
||||
\
|
||||
val |= (u64)read_sysreg(a32hi) << 32; \
|
||||
\
|
||||
return val; \
|
||||
}
|
||||
|
||||
CPUIF_MAP(ICC_PMR, ICC_PMR_EL1)
|
||||
CPUIF_MAP(ICC_AP0R0, ICC_AP0R0_EL1)
|
||||
CPUIF_MAP(ICC_AP0R1, ICC_AP0R1_EL1)
|
||||
@ -138,40 +58,6 @@ CPUIF_MAP(ICC_AP1R1, ICC_AP1R1_EL1)
|
||||
CPUIF_MAP(ICC_AP1R2, ICC_AP1R2_EL1)
|
||||
CPUIF_MAP(ICC_AP1R3, ICC_AP1R3_EL1)
|
||||
|
||||
CPUIF_MAP(ICH_HCR, ICH_HCR_EL2)
|
||||
CPUIF_MAP(ICH_VTR, ICH_VTR_EL2)
|
||||
CPUIF_MAP(ICH_MISR, ICH_MISR_EL2)
|
||||
CPUIF_MAP(ICH_EISR, ICH_EISR_EL2)
|
||||
CPUIF_MAP(ICH_ELRSR, ICH_ELRSR_EL2)
|
||||
CPUIF_MAP(ICH_VMCR, ICH_VMCR_EL2)
|
||||
CPUIF_MAP(ICH_AP0R3, ICH_AP0R3_EL2)
|
||||
CPUIF_MAP(ICH_AP0R2, ICH_AP0R2_EL2)
|
||||
CPUIF_MAP(ICH_AP0R1, ICH_AP0R1_EL2)
|
||||
CPUIF_MAP(ICH_AP0R0, ICH_AP0R0_EL2)
|
||||
CPUIF_MAP(ICH_AP1R3, ICH_AP1R3_EL2)
|
||||
CPUIF_MAP(ICH_AP1R2, ICH_AP1R2_EL2)
|
||||
CPUIF_MAP(ICH_AP1R1, ICH_AP1R1_EL2)
|
||||
CPUIF_MAP(ICH_AP1R0, ICH_AP1R0_EL2)
|
||||
CPUIF_MAP(ICC_HSRE, ICC_SRE_EL2)
|
||||
CPUIF_MAP(ICC_SRE, ICC_SRE_EL1)
|
||||
|
||||
CPUIF_MAP_LO_HI(ICH_LR15, ICH_LRC15, ICH_LR15_EL2)
|
||||
CPUIF_MAP_LO_HI(ICH_LR14, ICH_LRC14, ICH_LR14_EL2)
|
||||
CPUIF_MAP_LO_HI(ICH_LR13, ICH_LRC13, ICH_LR13_EL2)
|
||||
CPUIF_MAP_LO_HI(ICH_LR12, ICH_LRC12, ICH_LR12_EL2)
|
||||
CPUIF_MAP_LO_HI(ICH_LR11, ICH_LRC11, ICH_LR11_EL2)
|
||||
CPUIF_MAP_LO_HI(ICH_LR10, ICH_LRC10, ICH_LR10_EL2)
|
||||
CPUIF_MAP_LO_HI(ICH_LR9, ICH_LRC9, ICH_LR9_EL2)
|
||||
CPUIF_MAP_LO_HI(ICH_LR8, ICH_LRC8, ICH_LR8_EL2)
|
||||
CPUIF_MAP_LO_HI(ICH_LR7, ICH_LRC7, ICH_LR7_EL2)
|
||||
CPUIF_MAP_LO_HI(ICH_LR6, ICH_LRC6, ICH_LR6_EL2)
|
||||
CPUIF_MAP_LO_HI(ICH_LR5, ICH_LRC5, ICH_LR5_EL2)
|
||||
CPUIF_MAP_LO_HI(ICH_LR4, ICH_LRC4, ICH_LR4_EL2)
|
||||
CPUIF_MAP_LO_HI(ICH_LR3, ICH_LRC3, ICH_LR3_EL2)
|
||||
CPUIF_MAP_LO_HI(ICH_LR2, ICH_LRC2, ICH_LR2_EL2)
|
||||
CPUIF_MAP_LO_HI(ICH_LR1, ICH_LRC1, ICH_LR1_EL2)
|
||||
CPUIF_MAP_LO_HI(ICH_LR0, ICH_LRC0, ICH_LR0_EL2)
|
||||
|
||||
#define read_gicreg(r) read_##r()
|
||||
#define write_gicreg(v, r) write_##r(v)
|
||||
|
||||
|
@ -1,239 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2012 - Virtual Open Systems and Columbia University
|
||||
* Author: Christoffer Dall <c.dall@virtualopensystems.com>
|
||||
*/
|
||||
|
||||
#ifndef __ARM_KVM_ARM_H__
|
||||
#define __ARM_KVM_ARM_H__
|
||||
|
||||
#include <linux/const.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* Hyp Configuration Register (HCR) bits */
|
||||
#define HCR_TGE (1 << 27)
|
||||
#define HCR_TVM (1 << 26)
|
||||
#define HCR_TTLB (1 << 25)
|
||||
#define HCR_TPU (1 << 24)
|
||||
#define HCR_TPC (1 << 23)
|
||||
#define HCR_TSW (1 << 22)
|
||||
#define HCR_TAC (1 << 21)
|
||||
#define HCR_TIDCP (1 << 20)
|
||||
#define HCR_TSC (1 << 19)
|
||||
#define HCR_TID3 (1 << 18)
|
||||
#define HCR_TID2 (1 << 17)
|
||||
#define HCR_TID1 (1 << 16)
|
||||
#define HCR_TID0 (1 << 15)
|
||||
#define HCR_TWE (1 << 14)
|
||||
#define HCR_TWI (1 << 13)
|
||||
#define HCR_DC (1 << 12)
|
||||
#define HCR_BSU (3 << 10)
|
||||
#define HCR_BSU_IS (1 << 10)
|
||||
#define HCR_FB (1 << 9)
|
||||
#define HCR_VA (1 << 8)
|
||||
#define HCR_VI (1 << 7)
|
||||
#define HCR_VF (1 << 6)
|
||||
#define HCR_AMO (1 << 5)
|
||||
#define HCR_IMO (1 << 4)
|
||||
#define HCR_FMO (1 << 3)
|
||||
#define HCR_PTW (1 << 2)
|
||||
#define HCR_SWIO (1 << 1)
|
||||
#define HCR_VM 1
|
||||
|
||||
/*
|
||||
* The bits we set in HCR:
|
||||
* TAC: Trap ACTLR
|
||||
* TSC: Trap SMC
|
||||
* TVM: Trap VM ops (until MMU and caches are on)
|
||||
* TSW: Trap cache operations by set/way
|
||||
* TWI: Trap WFI
|
||||
* TWE: Trap WFE
|
||||
* TIDCP: Trap L2CTLR/L2ECTLR
|
||||
* BSU_IS: Upgrade barriers to the inner shareable domain
|
||||
* FB: Force broadcast of all maintainance operations
|
||||
* AMO: Override CPSR.A and enable signaling with VA
|
||||
* IMO: Override CPSR.I and enable signaling with VI
|
||||
* FMO: Override CPSR.F and enable signaling with VF
|
||||
* SWIO: Turn set/way invalidates into set/way clean+invalidate
|
||||
*/
|
||||
#define HCR_GUEST_MASK (HCR_TSC | HCR_TSW | HCR_TWI | HCR_VM | HCR_BSU_IS | \
|
||||
HCR_FB | HCR_TAC | HCR_AMO | HCR_IMO | HCR_FMO | \
|
||||
HCR_TVM | HCR_TWE | HCR_SWIO | HCR_TIDCP)
|
||||
|
||||
/* System Control Register (SCTLR) bits */
|
||||
#define SCTLR_TE (1 << 30)
|
||||
#define SCTLR_EE (1 << 25)
|
||||
#define SCTLR_V (1 << 13)
|
||||
|
||||
/* Hyp System Control Register (HSCTLR) bits */
|
||||
#define HSCTLR_TE (1 << 30)
|
||||
#define HSCTLR_EE (1 << 25)
|
||||
#define HSCTLR_FI (1 << 21)
|
||||
#define HSCTLR_WXN (1 << 19)
|
||||
#define HSCTLR_I (1 << 12)
|
||||
#define HSCTLR_C (1 << 2)
|
||||
#define HSCTLR_A (1 << 1)
|
||||
#define HSCTLR_M 1
|
||||
#define HSCTLR_MASK (HSCTLR_M | HSCTLR_A | HSCTLR_C | HSCTLR_I | \
|
||||
HSCTLR_WXN | HSCTLR_FI | HSCTLR_EE | HSCTLR_TE)
|
||||
|
||||
/* TTBCR and HTCR Registers bits */
|
||||
#define TTBCR_EAE (1 << 31)
|
||||
#define TTBCR_IMP (1 << 30)
|
||||
#define TTBCR_SH1 (3 << 28)
|
||||
#define TTBCR_ORGN1 (3 << 26)
|
||||
#define TTBCR_IRGN1 (3 << 24)
|
||||
#define TTBCR_EPD1 (1 << 23)
|
||||
#define TTBCR_A1 (1 << 22)
|
||||
#define TTBCR_T1SZ (7 << 16)
|
||||
#define TTBCR_SH0 (3 << 12)
|
||||
#define TTBCR_ORGN0 (3 << 10)
|
||||
#define TTBCR_IRGN0 (3 << 8)
|
||||
#define TTBCR_EPD0 (1 << 7)
|
||||
#define TTBCR_T0SZ (7 << 0)
|
||||
#define HTCR_MASK (TTBCR_T0SZ | TTBCR_IRGN0 | TTBCR_ORGN0 | TTBCR_SH0)
|
||||
|
||||
/* Hyp System Trap Register */
|
||||
#define HSTR_T(x) (1 << x)
|
||||
#define HSTR_TTEE (1 << 16)
|
||||
#define HSTR_TJDBX (1 << 17)
|
||||
|
||||
/* Hyp Coprocessor Trap Register */
|
||||
#define HCPTR_TCP(x) (1 << x)
|
||||
#define HCPTR_TCP_MASK (0x3fff)
|
||||
#define HCPTR_TASE (1 << 15)
|
||||
#define HCPTR_TTA (1 << 20)
|
||||
#define HCPTR_TCPAC (1 << 31)
|
||||
|
||||
/* Hyp Debug Configuration Register bits */
|
||||
#define HDCR_TDRA (1 << 11)
|
||||
#define HDCR_TDOSA (1 << 10)
|
||||
#define HDCR_TDA (1 << 9)
|
||||
#define HDCR_TDE (1 << 8)
|
||||
#define HDCR_HPME (1 << 7)
|
||||
#define HDCR_TPM (1 << 6)
|
||||
#define HDCR_TPMCR (1 << 5)
|
||||
#define HDCR_HPMN_MASK (0x1F)
|
||||
|
||||
/*
|
||||
* The architecture supports 40-bit IPA as input to the 2nd stage translations
|
||||
* and PTRS_PER_S2_PGD becomes 1024, because each entry covers 1GB of address
|
||||
* space.
|
||||
*/
|
||||
#define KVM_PHYS_SHIFT (40)
|
||||
|
||||
#define PTRS_PER_S2_PGD (_AC(1, ULL) << (KVM_PHYS_SHIFT - 30))
|
||||
|
||||
/* Virtualization Translation Control Register (VTCR) bits */
|
||||
#define VTCR_SH0 (3 << 12)
|
||||
#define VTCR_ORGN0 (3 << 10)
|
||||
#define VTCR_IRGN0 (3 << 8)
|
||||
#define VTCR_SL0 (3 << 6)
|
||||
#define VTCR_S (1 << 4)
|
||||
#define VTCR_T0SZ (0xf)
|
||||
#define VTCR_MASK (VTCR_SH0 | VTCR_ORGN0 | VTCR_IRGN0 | VTCR_SL0 | \
|
||||
VTCR_S | VTCR_T0SZ)
|
||||
#define VTCR_HTCR_SH (VTCR_SH0 | VTCR_ORGN0 | VTCR_IRGN0)
|
||||
#define VTCR_SL_L2 (0 << 6) /* Starting-level: 2 */
|
||||
#define VTCR_SL_L1 (1 << 6) /* Starting-level: 1 */
|
||||
#define KVM_VTCR_SL0 VTCR_SL_L1
|
||||
/* stage-2 input address range defined as 2^(32-T0SZ) */
|
||||
#define KVM_T0SZ (32 - KVM_PHYS_SHIFT)
|
||||
#define KVM_VTCR_T0SZ (KVM_T0SZ & VTCR_T0SZ)
|
||||
#define KVM_VTCR_S ((KVM_VTCR_T0SZ << 1) & VTCR_S)
|
||||
|
||||
/* Virtualization Translation Table Base Register (VTTBR) bits */
|
||||
#if KVM_VTCR_SL0 == VTCR_SL_L2 /* see ARM DDI 0406C: B4-1720 */
|
||||
#define VTTBR_X (14 - KVM_T0SZ)
|
||||
#else
|
||||
#define VTTBR_X (5 - KVM_T0SZ)
|
||||
#endif
|
||||
#define VTTBR_CNP_BIT _AC(1, UL)
|
||||
#define VTTBR_BADDR_MASK (((_AC(1, ULL) << (40 - VTTBR_X)) - 1) << VTTBR_X)
|
||||
#define VTTBR_VMID_SHIFT _AC(48, ULL)
|
||||
#define VTTBR_VMID_MASK(size) (_AT(u64, (1 << size) - 1) << VTTBR_VMID_SHIFT)
|
||||
|
||||
/* Hyp Syndrome Register (HSR) bits */
|
||||
#define HSR_EC_SHIFT (26)
|
||||
#define HSR_EC (_AC(0x3f, UL) << HSR_EC_SHIFT)
|
||||
#define HSR_IL (_AC(1, UL) << 25)
|
||||
#define HSR_ISS (HSR_IL - 1)
|
||||
#define HSR_ISV_SHIFT (24)
|
||||
#define HSR_ISV (_AC(1, UL) << HSR_ISV_SHIFT)
|
||||
#define HSR_SRT_SHIFT (16)
|
||||
#define HSR_SRT_MASK (0xf << HSR_SRT_SHIFT)
|
||||
#define HSR_CM (1 << 8)
|
||||
#define HSR_FSC (0x3f)
|
||||
#define HSR_FSC_TYPE (0x3c)
|
||||
#define HSR_SSE (1 << 21)
|
||||
#define HSR_WNR (1 << 6)
|
||||
#define HSR_CV_SHIFT (24)
|
||||
#define HSR_CV (_AC(1, UL) << HSR_CV_SHIFT)
|
||||
#define HSR_COND_SHIFT (20)
|
||||
#define HSR_COND (_AC(0xf, UL) << HSR_COND_SHIFT)
|
||||
|
||||
#define FSC_FAULT (0x04)
|
||||
#define FSC_ACCESS (0x08)
|
||||
#define FSC_PERM (0x0c)
|
||||
#define FSC_SEA (0x10)
|
||||
#define FSC_SEA_TTW0 (0x14)
|
||||
#define FSC_SEA_TTW1 (0x15)
|
||||
#define FSC_SEA_TTW2 (0x16)
|
||||
#define FSC_SEA_TTW3 (0x17)
|
||||
#define FSC_SECC (0x18)
|
||||
#define FSC_SECC_TTW0 (0x1c)
|
||||
#define FSC_SECC_TTW1 (0x1d)
|
||||
#define FSC_SECC_TTW2 (0x1e)
|
||||
#define FSC_SECC_TTW3 (0x1f)
|
||||
|
||||
/* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
|
||||
#define HPFAR_MASK (~0xf)
|
||||
|
||||
#define HSR_EC_UNKNOWN (0x00)
|
||||
#define HSR_EC_WFI (0x01)
|
||||
#define HSR_EC_CP15_32 (0x03)
|
||||
#define HSR_EC_CP15_64 (0x04)
|
||||
#define HSR_EC_CP14_MR (0x05)
|
||||
#define HSR_EC_CP14_LS (0x06)
|
||||
#define HSR_EC_CP_0_13 (0x07)
|
||||
#define HSR_EC_CP10_ID (0x08)
|
||||
#define HSR_EC_JAZELLE (0x09)
|
||||
#define HSR_EC_BXJ (0x0A)
|
||||
#define HSR_EC_CP14_64 (0x0C)
|
||||
#define HSR_EC_SVC_HYP (0x11)
|
||||
#define HSR_EC_HVC (0x12)
|
||||
#define HSR_EC_SMC (0x13)
|
||||
#define HSR_EC_IABT (0x20)
|
||||
#define HSR_EC_IABT_HYP (0x21)
|
||||
#define HSR_EC_DABT (0x24)
|
||||
#define HSR_EC_DABT_HYP (0x25)
|
||||
#define HSR_EC_MAX (0x3f)
|
||||
|
||||
#define HSR_WFI_IS_WFE (_AC(1, UL) << 0)
|
||||
|
||||
#define HSR_HVC_IMM_MASK ((_AC(1, UL) << 16) - 1)
|
||||
|
||||
#define HSR_DABT_S1PTW (_AC(1, UL) << 7)
|
||||
#define HSR_DABT_CM (_AC(1, UL) << 8)
|
||||
|
||||
#define kvm_arm_exception_type \
|
||||
{0, "RESET" }, \
|
||||
{1, "UNDEFINED" }, \
|
||||
{2, "SOFTWARE" }, \
|
||||
{3, "PREF_ABORT" }, \
|
||||
{4, "DATA_ABORT" }, \
|
||||
{5, "IRQ" }, \
|
||||
{6, "FIQ" }, \
|
||||
{7, "HVC" }
|
||||
|
||||
#define HSRECN(x) { HSR_EC_##x, #x }
|
||||
|
||||
#define kvm_arm_exception_class \
|
||||
HSRECN(UNKNOWN), HSRECN(WFI), HSRECN(CP15_32), HSRECN(CP15_64), \
|
||||
HSRECN(CP14_MR), HSRECN(CP14_LS), HSRECN(CP_0_13), HSRECN(CP10_ID), \
|
||||
HSRECN(JAZELLE), HSRECN(BXJ), HSRECN(CP14_64), HSRECN(SVC_HYP), \
|
||||
HSRECN(HVC), HSRECN(SMC), HSRECN(IABT), HSRECN(IABT_HYP), \
|
||||
HSRECN(DABT), HSRECN(DABT_HYP)
|
||||
|
||||
|
||||
#endif /* __ARM_KVM_ARM_H__ */
|
@ -1,77 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2012 - Virtual Open Systems and Columbia University
|
||||
* Author: Christoffer Dall <c.dall@virtualopensystems.com>
|
||||
*/
|
||||
|
||||
#ifndef __ARM_KVM_ASM_H__
|
||||
#define __ARM_KVM_ASM_H__
|
||||
|
||||
#include <asm/virt.h>
|
||||
|
||||
#define ARM_EXIT_WITH_ABORT_BIT 31
|
||||
#define ARM_EXCEPTION_CODE(x) ((x) & ~(1U << ARM_EXIT_WITH_ABORT_BIT))
|
||||
#define ARM_EXCEPTION_IS_TRAP(x) \
|
||||
(ARM_EXCEPTION_CODE((x)) == ARM_EXCEPTION_PREF_ABORT || \
|
||||
ARM_EXCEPTION_CODE((x)) == ARM_EXCEPTION_DATA_ABORT || \
|
||||
ARM_EXCEPTION_CODE((x)) == ARM_EXCEPTION_HVC)
|
||||
#define ARM_ABORT_PENDING(x) !!((x) & (1U << ARM_EXIT_WITH_ABORT_BIT))
|
||||
|
||||
#define ARM_EXCEPTION_RESET 0
|
||||
#define ARM_EXCEPTION_UNDEFINED 1
|
||||
#define ARM_EXCEPTION_SOFTWARE 2
|
||||
#define ARM_EXCEPTION_PREF_ABORT 3
|
||||
#define ARM_EXCEPTION_DATA_ABORT 4
|
||||
#define ARM_EXCEPTION_IRQ 5
|
||||
#define ARM_EXCEPTION_FIQ 6
|
||||
#define ARM_EXCEPTION_HVC 7
|
||||
#define ARM_EXCEPTION_HYP_GONE HVC_STUB_ERR
|
||||
/*
|
||||
* The rr_lo_hi macro swaps a pair of registers depending on
|
||||
* current endianness. It is used in conjunction with ldrd and strd
|
||||
* instructions that load/store a 64-bit value from/to memory to/from
|
||||
* a pair of registers which are used with the mrrc and mcrr instructions.
|
||||
* If used with the ldrd/strd instructions, the a1 parameter is the first
|
||||
* source/destination register and the a2 parameter is the second
|
||||
* source/destination register. Note that the ldrd/strd instructions
|
||||
* already swap the bytes within the words correctly according to the
|
||||
* endianness setting, but the order of the registers need to be effectively
|
||||
* swapped when used with the mrrc/mcrr instructions.
|
||||
*/
|
||||
#ifdef CONFIG_CPU_ENDIAN_BE8
|
||||
#define rr_lo_hi(a1, a2) a2, a1
|
||||
#else
|
||||
#define rr_lo_hi(a1, a2) a1, a2
|
||||
#endif
|
||||
|
||||
#define kvm_ksym_ref(kva) (kva)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
struct kvm;
|
||||
struct kvm_vcpu;
|
||||
|
||||
extern char __kvm_hyp_init[];
|
||||
extern char __kvm_hyp_init_end[];
|
||||
|
||||
extern void __kvm_flush_vm_context(void);
|
||||
extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
|
||||
extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
|
||||
extern void __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu);
|
||||
|
||||
extern void __kvm_timer_set_cntvoff(u32 cntvoff_low, u32 cntvoff_high);
|
||||
|
||||
/* no VHE on 32-bit :( */
|
||||
static inline int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu) { BUG(); return 0; }
|
||||
|
||||
extern int __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu);
|
||||
|
||||
extern void __init_stage2_translation(void);
|
||||
|
||||
extern u64 __vgic_v3_get_ich_vtr_el2(void);
|
||||
extern u64 __vgic_v3_read_vmcr(void);
|
||||
extern void __vgic_v3_write_vmcr(u32 vmcr);
|
||||
extern void __vgic_v3_init_lrs(void);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __ARM_KVM_ASM_H__ */
|
@ -1,36 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2012 Rusty Russell IBM Corporation
|
||||
*/
|
||||
|
||||
#ifndef __ARM_KVM_COPROC_H__
|
||||
#define __ARM_KVM_COPROC_H__
|
||||
#include <linux/kvm_host.h>
|
||||
|
||||
void kvm_reset_coprocs(struct kvm_vcpu *vcpu);
|
||||
|
||||
struct kvm_coproc_target_table {
|
||||
unsigned target;
|
||||
const struct coproc_reg *table;
|
||||
size_t num;
|
||||
};
|
||||
void kvm_register_target_coproc_table(struct kvm_coproc_target_table *table);
|
||||
|
||||
int kvm_handle_cp10_id(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||
int kvm_handle_cp_0_13_access(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||
int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||
int kvm_handle_cp14_32(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||
int kvm_handle_cp14_64(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||
int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||
int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||
|
||||
unsigned long kvm_arm_num_guest_msrs(struct kvm_vcpu *vcpu);
|
||||
int kvm_arm_copy_msrindices(struct kvm_vcpu *vcpu, u64 __user *uindices);
|
||||
void kvm_coproc_table_init(void);
|
||||
|
||||
struct kvm_one_reg;
|
||||
int kvm_arm_copy_coproc_indices(struct kvm_vcpu *vcpu, u64 __user *uindices);
|
||||
int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
|
||||
int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
|
||||
unsigned long kvm_arm_num_coproc_regs(struct kvm_vcpu *vcpu);
|
||||
#endif /* __ARM_KVM_COPROC_H__ */
|
@ -1,372 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2012 - Virtual Open Systems and Columbia University
|
||||
* Author: Christoffer Dall <c.dall@virtualopensystems.com>
|
||||
*/
|
||||
|
||||
#ifndef __ARM_KVM_EMULATE_H__
|
||||
#define __ARM_KVM_EMULATE_H__
|
||||
|
||||
#include <linux/kvm_host.h>
|
||||
#include <asm/kvm_asm.h>
|
||||
#include <asm/kvm_arm.h>
|
||||
#include <asm/cputype.h>
|
||||
|
||||
/* arm64 compatibility macros */
|
||||
#define PSR_AA32_MODE_FIQ FIQ_MODE
|
||||
#define PSR_AA32_MODE_SVC SVC_MODE
|
||||
#define PSR_AA32_MODE_ABT ABT_MODE
|
||||
#define PSR_AA32_MODE_UND UND_MODE
|
||||
#define PSR_AA32_T_BIT PSR_T_BIT
|
||||
#define PSR_AA32_F_BIT PSR_F_BIT
|
||||
#define PSR_AA32_I_BIT PSR_I_BIT
|
||||
#define PSR_AA32_A_BIT PSR_A_BIT
|
||||
#define PSR_AA32_E_BIT PSR_E_BIT
|
||||
#define PSR_AA32_IT_MASK PSR_IT_MASK
|
||||
#define PSR_AA32_GE_MASK 0x000f0000
|
||||
#define PSR_AA32_DIT_BIT 0x00200000
|
||||
#define PSR_AA32_PAN_BIT 0x00400000
|
||||
#define PSR_AA32_SSBS_BIT 0x00800000
|
||||
#define PSR_AA32_Q_BIT PSR_Q_BIT
|
||||
#define PSR_AA32_V_BIT PSR_V_BIT
|
||||
#define PSR_AA32_C_BIT PSR_C_BIT
|
||||
#define PSR_AA32_Z_BIT PSR_Z_BIT
|
||||
#define PSR_AA32_N_BIT PSR_N_BIT
|
||||
|
||||
unsigned long *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num);
|
||||
|
||||
static inline unsigned long *vcpu_reg32(struct kvm_vcpu *vcpu, u8 reg_num)
|
||||
{
|
||||
return vcpu_reg(vcpu, reg_num);
|
||||
}
|
||||
|
||||
unsigned long *__vcpu_spsr(struct kvm_vcpu *vcpu);
|
||||
|
||||
static inline unsigned long vpcu_read_spsr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return *__vcpu_spsr(vcpu);
|
||||
}
|
||||
|
||||
static inline void vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long v)
|
||||
{
|
||||
*__vcpu_spsr(vcpu) = v;
|
||||
}
|
||||
|
||||
static inline unsigned long host_spsr_to_spsr32(unsigned long spsr)
|
||||
{
|
||||
return spsr;
|
||||
}
|
||||
|
||||
static inline unsigned long vcpu_get_reg(struct kvm_vcpu *vcpu,
|
||||
u8 reg_num)
|
||||
{
|
||||
return *vcpu_reg(vcpu, reg_num);
|
||||
}
|
||||
|
||||
static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
|
||||
unsigned long val)
|
||||
{
|
||||
*vcpu_reg(vcpu, reg_num) = val;
|
||||
}
|
||||
|
||||
bool kvm_condition_valid32(const struct kvm_vcpu *vcpu);
|
||||
void kvm_skip_instr32(struct kvm_vcpu *vcpu, bool is_wide_instr);
|
||||
void kvm_inject_undef32(struct kvm_vcpu *vcpu);
|
||||
void kvm_inject_dabt32(struct kvm_vcpu *vcpu, unsigned long addr);
|
||||
void kvm_inject_pabt32(struct kvm_vcpu *vcpu, unsigned long addr);
|
||||
void kvm_inject_vabt(struct kvm_vcpu *vcpu);
|
||||
|
||||
static inline void kvm_inject_undefined(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
kvm_inject_undef32(vcpu);
|
||||
}
|
||||
|
||||
static inline void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr)
|
||||
{
|
||||
kvm_inject_dabt32(vcpu, addr);
|
||||
}
|
||||
|
||||
static inline void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
|
||||
{
|
||||
kvm_inject_pabt32(vcpu, addr);
|
||||
}
|
||||
|
||||
static inline bool kvm_condition_valid(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return kvm_condition_valid32(vcpu);
|
||||
}
|
||||
|
||||
static inline void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr)
|
||||
{
|
||||
kvm_skip_instr32(vcpu, is_wide_instr);
|
||||
}
|
||||
|
||||
static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
vcpu->arch.hcr = HCR_GUEST_MASK;
|
||||
}
|
||||
|
||||
static inline unsigned long *vcpu_hcr(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return (unsigned long *)&vcpu->arch.hcr;
|
||||
}
|
||||
|
||||
static inline void vcpu_clear_wfx_traps(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
vcpu->arch.hcr &= ~HCR_TWE;
|
||||
}
|
||||
|
||||
static inline void vcpu_set_wfx_traps(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
vcpu->arch.hcr |= HCR_TWE;
|
||||
}
|
||||
|
||||
static inline bool vcpu_mode_is_32bit(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline unsigned long *vcpu_pc(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return &vcpu->arch.ctxt.gp_regs.usr_regs.ARM_pc;
|
||||
}
|
||||
|
||||
static inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return (unsigned long *)&vcpu->arch.ctxt.gp_regs.usr_regs.ARM_cpsr;
|
||||
}
|
||||
|
||||
static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
*vcpu_cpsr(vcpu) |= PSR_T_BIT;
|
||||
}
|
||||
|
||||
static inline bool mode_has_spsr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long cpsr_mode = vcpu->arch.ctxt.gp_regs.usr_regs.ARM_cpsr & MODE_MASK;
|
||||
return (cpsr_mode > USR_MODE && cpsr_mode < SYSTEM_MODE);
|
||||
}
|
||||
|
||||
static inline bool vcpu_mode_priv(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long cpsr_mode = vcpu->arch.ctxt.gp_regs.usr_regs.ARM_cpsr & MODE_MASK;
|
||||
return cpsr_mode > USR_MODE;
|
||||
}
|
||||
|
||||
static inline u32 kvm_vcpu_get_hsr(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return vcpu->arch.fault.hsr;
|
||||
}
|
||||
|
||||
static inline int kvm_vcpu_get_condition(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u32 hsr = kvm_vcpu_get_hsr(vcpu);
|
||||
|
||||
if (hsr & HSR_CV)
|
||||
return (hsr & HSR_COND) >> HSR_COND_SHIFT;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline unsigned long kvm_vcpu_get_hfar(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return vcpu->arch.fault.hxfar;
|
||||
}
|
||||
|
||||
static inline phys_addr_t kvm_vcpu_get_fault_ipa(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return ((phys_addr_t)vcpu->arch.fault.hpfar & HPFAR_MASK) << 8;
|
||||
}
|
||||
|
||||
static inline bool kvm_vcpu_dabt_isvalid(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return kvm_vcpu_get_hsr(vcpu) & HSR_ISV;
|
||||
}
|
||||
|
||||
static inline unsigned long kvm_vcpu_dabt_iss_nisv_sanitized(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return kvm_vcpu_get_hsr(vcpu) & (HSR_CM | HSR_WNR | HSR_FSC);
|
||||
}
|
||||
|
||||
static inline bool kvm_vcpu_dabt_iswrite(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return kvm_vcpu_get_hsr(vcpu) & HSR_WNR;
|
||||
}
|
||||
|
||||
static inline bool kvm_vcpu_dabt_issext(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return kvm_vcpu_get_hsr(vcpu) & HSR_SSE;
|
||||
}
|
||||
|
||||
static inline bool kvm_vcpu_dabt_issf(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int kvm_vcpu_dabt_get_rd(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return (kvm_vcpu_get_hsr(vcpu) & HSR_SRT_MASK) >> HSR_SRT_SHIFT;
|
||||
}
|
||||
|
||||
static inline bool kvm_vcpu_dabt_iss1tw(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return kvm_vcpu_get_hsr(vcpu) & HSR_DABT_S1PTW;
|
||||
}
|
||||
|
||||
static inline bool kvm_vcpu_dabt_is_cm(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return !!(kvm_vcpu_get_hsr(vcpu) & HSR_DABT_CM);
|
||||
}
|
||||
|
||||
/* Get Access Size from a data abort */
|
||||
static inline unsigned int kvm_vcpu_dabt_get_as(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
switch ((kvm_vcpu_get_hsr(vcpu) >> 22) & 0x3) {
|
||||
case 0:
|
||||
return 1;
|
||||
case 1:
|
||||
return 2;
|
||||
case 2:
|
||||
return 4;
|
||||
default:
|
||||
kvm_err("Hardware is weird: SAS 0b11 is reserved\n");
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* This one is not specific to Data Abort */
|
||||
static inline bool kvm_vcpu_trap_il_is32bit(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return kvm_vcpu_get_hsr(vcpu) & HSR_IL;
|
||||
}
|
||||
|
||||
static inline u8 kvm_vcpu_trap_get_class(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return kvm_vcpu_get_hsr(vcpu) >> HSR_EC_SHIFT;
|
||||
}
|
||||
|
||||
static inline bool kvm_vcpu_trap_is_iabt(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return kvm_vcpu_trap_get_class(vcpu) == HSR_EC_IABT;
|
||||
}
|
||||
|
||||
static inline u8 kvm_vcpu_trap_get_fault(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return kvm_vcpu_get_hsr(vcpu) & HSR_FSC;
|
||||
}
|
||||
|
||||
static inline u8 kvm_vcpu_trap_get_fault_type(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return kvm_vcpu_get_hsr(vcpu) & HSR_FSC_TYPE;
|
||||
}
|
||||
|
||||
static inline bool kvm_vcpu_dabt_isextabt(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
switch (kvm_vcpu_trap_get_fault(vcpu)) {
|
||||
case FSC_SEA:
|
||||
case FSC_SEA_TTW0:
|
||||
case FSC_SEA_TTW1:
|
||||
case FSC_SEA_TTW2:
|
||||
case FSC_SEA_TTW3:
|
||||
case FSC_SECC:
|
||||
case FSC_SECC_TTW0:
|
||||
case FSC_SECC_TTW1:
|
||||
case FSC_SECC_TTW2:
|
||||
case FSC_SECC_TTW3:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (kvm_vcpu_trap_is_iabt(vcpu))
|
||||
return false;
|
||||
|
||||
return kvm_vcpu_dabt_iswrite(vcpu);
|
||||
}
|
||||
|
||||
static inline u32 kvm_vcpu_hvc_get_imm(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return kvm_vcpu_get_hsr(vcpu) & HSR_HVC_IMM_MASK;
|
||||
}
|
||||
|
||||
static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return vcpu_cp15(vcpu, c0_MPIDR) & MPIDR_HWID_BITMASK;
|
||||
}
|
||||
|
||||
static inline bool kvm_arm_get_vcpu_workaround_2_flag(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void kvm_arm_set_vcpu_workaround_2_flag(struct kvm_vcpu *vcpu,
|
||||
bool flag)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
*vcpu_cpsr(vcpu) |= PSR_E_BIT;
|
||||
}
|
||||
|
||||
static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return !!(*vcpu_cpsr(vcpu) & PSR_E_BIT);
|
||||
}
|
||||
|
||||
static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
|
||||
unsigned long data,
|
||||
unsigned int len)
|
||||
{
|
||||
if (kvm_vcpu_is_be(vcpu)) {
|
||||
switch (len) {
|
||||
case 1:
|
||||
return data & 0xff;
|
||||
case 2:
|
||||
return be16_to_cpu(data & 0xffff);
|
||||
default:
|
||||
return be32_to_cpu(data);
|
||||
}
|
||||
} else {
|
||||
switch (len) {
|
||||
case 1:
|
||||
return data & 0xff;
|
||||
case 2:
|
||||
return le16_to_cpu(data & 0xffff);
|
||||
default:
|
||||
return le32_to_cpu(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned long vcpu_data_host_to_guest(struct kvm_vcpu *vcpu,
|
||||
unsigned long data,
|
||||
unsigned int len)
|
||||
{
|
||||
if (kvm_vcpu_is_be(vcpu)) {
|
||||
switch (len) {
|
||||
case 1:
|
||||
return data & 0xff;
|
||||
case 2:
|
||||
return cpu_to_be16(data & 0xffff);
|
||||
default:
|
||||
return cpu_to_be32(data);
|
||||
}
|
||||
} else {
|
||||
switch (len) {
|
||||
case 1:
|
||||
return data & 0xff;
|
||||
case 2:
|
||||
return cpu_to_le16(data & 0xffff);
|
||||
default:
|
||||
return cpu_to_le32(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void vcpu_ptrauth_setup_lazy(struct kvm_vcpu *vcpu) {}
|
||||
|
||||
#endif /* __ARM_KVM_EMULATE_H__ */
|
@ -1,456 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2012 - Virtual Open Systems and Columbia University
|
||||
* Author: Christoffer Dall <c.dall@virtualopensystems.com>
|
||||
*/
|
||||
|
||||
#ifndef __ARM_KVM_HOST_H__
|
||||
#define __ARM_KVM_HOST_H__
|
||||
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kvm_types.h>
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/kvm.h>
|
||||
#include <asm/kvm_asm.h>
|
||||
#include <asm/fpstate.h>
|
||||
#include <kvm/arm_arch_timer.h>
|
||||
|
||||
#define __KVM_HAVE_ARCH_INTC_INITIALIZED
|
||||
|
||||
#define KVM_USER_MEM_SLOTS 32
|
||||
#define KVM_HAVE_ONE_REG
|
||||
#define KVM_HALT_POLL_NS_DEFAULT 500000
|
||||
|
||||
#define KVM_VCPU_MAX_FEATURES 2
|
||||
|
||||
#include <kvm/arm_vgic.h>
|
||||
|
||||
|
||||
#ifdef CONFIG_ARM_GIC_V3
|
||||
#define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
|
||||
#else
|
||||
#define KVM_MAX_VCPUS VGIC_V2_MAX_CPUS
|
||||
#endif
|
||||
|
||||
#define KVM_REQ_SLEEP \
|
||||
KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
|
||||
#define KVM_REQ_IRQ_PENDING KVM_ARCH_REQ(1)
|
||||
#define KVM_REQ_VCPU_RESET KVM_ARCH_REQ(2)
|
||||
#define KVM_REQ_RECORD_STEAL KVM_ARCH_REQ(3)
|
||||
|
||||
DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
|
||||
|
||||
static inline int kvm_arm_init_sve(void) { return 0; }
|
||||
|
||||
u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
|
||||
int __attribute_const__ kvm_target_cpu(void);
|
||||
int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
|
||||
void kvm_reset_coprocs(struct kvm_vcpu *vcpu);
|
||||
|
||||
struct kvm_vmid {
|
||||
/* The VMID generation used for the virt. memory system */
|
||||
u64 vmid_gen;
|
||||
u32 vmid;
|
||||
};
|
||||
|
||||
struct kvm_arch {
|
||||
/* The last vcpu id that ran on each physical CPU */
|
||||
int __percpu *last_vcpu_ran;
|
||||
|
||||
/*
|
||||
* Anything that is not used directly from assembly code goes
|
||||
* here.
|
||||
*/
|
||||
|
||||
/* The VMID generation used for the virt. memory system */
|
||||
struct kvm_vmid vmid;
|
||||
|
||||
/* Stage-2 page table */
|
||||
pgd_t *pgd;
|
||||
phys_addr_t pgd_phys;
|
||||
|
||||
/* Interrupt controller */
|
||||
struct vgic_dist vgic;
|
||||
int max_vcpus;
|
||||
|
||||
/* Mandated version of PSCI */
|
||||
u32 psci_version;
|
||||
|
||||
/*
|
||||
* If we encounter a data abort without valid instruction syndrome
|
||||
* information, report this to user space. User space can (and
|
||||
* should) opt in to this feature if KVM_CAP_ARM_NISV_TO_USER is
|
||||
* supported.
|
||||
*/
|
||||
bool return_nisv_io_abort_to_user;
|
||||
};
|
||||
|
||||
#define KVM_NR_MEM_OBJS 40
|
||||
|
||||
/*
|
||||
* We don't want allocation failures within the mmu code, so we preallocate
|
||||
* enough memory for a single page fault in a cache.
|
||||
*/
|
||||
struct kvm_mmu_memory_cache {
|
||||
int nobjs;
|
||||
void *objects[KVM_NR_MEM_OBJS];
|
||||
};
|
||||
|
||||
struct kvm_vcpu_fault_info {
|
||||
u32 hsr; /* Hyp Syndrome Register */
|
||||
u32 hxfar; /* Hyp Data/Inst. Fault Address Register */
|
||||
u32 hpfar; /* Hyp IPA Fault Address Register */
|
||||
};
|
||||
|
||||
/*
|
||||
* 0 is reserved as an invalid value.
|
||||
* Order should be kept in sync with the save/restore code.
|
||||
*/
|
||||
enum vcpu_sysreg {
|
||||
__INVALID_SYSREG__,
|
||||
c0_MPIDR, /* MultiProcessor ID Register */
|
||||
c0_CSSELR, /* Cache Size Selection Register */
|
||||
c1_SCTLR, /* System Control Register */
|
||||
c1_ACTLR, /* Auxiliary Control Register */
|
||||
c1_CPACR, /* Coprocessor Access Control */
|
||||
c2_TTBR0, /* Translation Table Base Register 0 */
|
||||
c2_TTBR0_high, /* TTBR0 top 32 bits */
|
||||
c2_TTBR1, /* Translation Table Base Register 1 */
|
||||
c2_TTBR1_high, /* TTBR1 top 32 bits */
|
||||
c2_TTBCR, /* Translation Table Base Control R. */
|
||||
c3_DACR, /* Domain Access Control Register */
|
||||
c5_DFSR, /* Data Fault Status Register */
|
||||
c5_IFSR, /* Instruction Fault Status Register */
|
||||
c5_ADFSR, /* Auxilary Data Fault Status R */
|
||||
c5_AIFSR, /* Auxilary Instrunction Fault Status R */
|
||||
c6_DFAR, /* Data Fault Address Register */
|
||||
c6_IFAR, /* Instruction Fault Address Register */
|
||||
c7_PAR, /* Physical Address Register */
|
||||
c7_PAR_high, /* PAR top 32 bits */
|
||||
c9_L2CTLR, /* Cortex A15/A7 L2 Control Register */
|
||||
c10_PRRR, /* Primary Region Remap Register */
|
||||
c10_NMRR, /* Normal Memory Remap Register */
|
||||
c12_VBAR, /* Vector Base Address Register */
|
||||
c13_CID, /* Context ID Register */
|
||||
c13_TID_URW, /* Thread ID, User R/W */
|
||||
c13_TID_URO, /* Thread ID, User R/O */
|
||||
c13_TID_PRIV, /* Thread ID, Privileged */
|
||||
c14_CNTKCTL, /* Timer Control Register (PL1) */
|
||||
c10_AMAIR0, /* Auxilary Memory Attribute Indirection Reg0 */
|
||||
c10_AMAIR1, /* Auxilary Memory Attribute Indirection Reg1 */
|
||||
NR_CP15_REGS /* Number of regs (incl. invalid) */
|
||||
};
|
||||
|
||||
struct kvm_cpu_context {
|
||||
struct kvm_regs gp_regs;
|
||||
struct vfp_hard_struct vfp;
|
||||
u32 cp15[NR_CP15_REGS];
|
||||
};
|
||||
|
||||
struct kvm_host_data {
|
||||
struct kvm_cpu_context host_ctxt;
|
||||
};
|
||||
|
||||
typedef struct kvm_host_data kvm_host_data_t;
|
||||
|
||||
static inline void kvm_init_host_cpu_context(struct kvm_cpu_context *cpu_ctxt)
|
||||
{
|
||||
/* The host's MPIDR is immutable, so let's set it up at boot time */
|
||||
cpu_ctxt->cp15[c0_MPIDR] = read_cpuid_mpidr();
|
||||
}
|
||||
|
||||
struct vcpu_reset_state {
|
||||
unsigned long pc;
|
||||
unsigned long r0;
|
||||
bool be;
|
||||
bool reset;
|
||||
};
|
||||
|
||||
struct kvm_vcpu_arch {
|
||||
struct kvm_cpu_context ctxt;
|
||||
|
||||
int target; /* Processor target */
|
||||
DECLARE_BITMAP(features, KVM_VCPU_MAX_FEATURES);
|
||||
|
||||
/* The CPU type we expose to the VM */
|
||||
u32 midr;
|
||||
|
||||
/* HYP trapping configuration */
|
||||
u32 hcr;
|
||||
|
||||
/* Exception Information */
|
||||
struct kvm_vcpu_fault_info fault;
|
||||
|
||||
/* Host FP context */
|
||||
struct kvm_cpu_context *host_cpu_context;
|
||||
|
||||
/* VGIC state */
|
||||
struct vgic_cpu vgic_cpu;
|
||||
struct arch_timer_cpu timer_cpu;
|
||||
|
||||
/*
|
||||
* Anything that is not used directly from assembly code goes
|
||||
* here.
|
||||
*/
|
||||
|
||||
/* vcpu power-off state */
|
||||
bool power_off;
|
||||
|
||||
/* Don't run the guest (internal implementation need) */
|
||||
bool pause;
|
||||
|
||||
/* Cache some mmu pages needed inside spinlock regions */
|
||||
struct kvm_mmu_memory_cache mmu_page_cache;
|
||||
|
||||
struct vcpu_reset_state reset_state;
|
||||
|
||||
/* Detect first run of a vcpu */
|
||||
bool has_run_once;
|
||||
};
|
||||
|
||||
struct kvm_vm_stat {
|
||||
ulong remote_tlb_flush;
|
||||
};
|
||||
|
||||
struct kvm_vcpu_stat {
|
||||
u64 halt_successful_poll;
|
||||
u64 halt_attempted_poll;
|
||||
u64 halt_poll_invalid;
|
||||
u64 halt_wakeup;
|
||||
u64 hvc_exit_stat;
|
||||
u64 wfe_exit_stat;
|
||||
u64 wfi_exit_stat;
|
||||
u64 mmio_exit_user;
|
||||
u64 mmio_exit_kernel;
|
||||
u64 exits;
|
||||
};
|
||||
|
||||
#define vcpu_cp15(v,r) (v)->arch.ctxt.cp15[r]
|
||||
|
||||
int kvm_vcpu_preferred_target(struct kvm_vcpu_init *init);
|
||||
unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
|
||||
int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
|
||||
int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
|
||||
int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
|
||||
|
||||
unsigned long __kvm_call_hyp(void *hypfn, ...);
|
||||
|
||||
/*
|
||||
* The has_vhe() part doesn't get emitted, but is used for type-checking.
|
||||
*/
|
||||
#define kvm_call_hyp(f, ...) \
|
||||
do { \
|
||||
if (has_vhe()) { \
|
||||
f(__VA_ARGS__); \
|
||||
} else { \
|
||||
__kvm_call_hyp(kvm_ksym_ref(f), ##__VA_ARGS__); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define kvm_call_hyp_ret(f, ...) \
|
||||
({ \
|
||||
typeof(f(__VA_ARGS__)) ret; \
|
||||
\
|
||||
if (has_vhe()) { \
|
||||
ret = f(__VA_ARGS__); \
|
||||
} else { \
|
||||
ret = __kvm_call_hyp(kvm_ksym_ref(f), \
|
||||
##__VA_ARGS__); \
|
||||
} \
|
||||
\
|
||||
ret; \
|
||||
})
|
||||
|
||||
void force_vm_exit(const cpumask_t *mask);
|
||||
int __kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
|
||||
struct kvm_vcpu_events *events);
|
||||
|
||||
int __kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
|
||||
struct kvm_vcpu_events *events);
|
||||
|
||||
#define KVM_ARCH_WANT_MMU_NOTIFIER
|
||||
int kvm_unmap_hva_range(struct kvm *kvm,
|
||||
unsigned long start, unsigned long end);
|
||||
int kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
|
||||
|
||||
unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
|
||||
int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
|
||||
int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
|
||||
int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
|
||||
|
||||
void kvm_arm_halt_guest(struct kvm *kvm);
|
||||
void kvm_arm_resume_guest(struct kvm *kvm);
|
||||
|
||||
int kvm_arm_copy_coproc_indices(struct kvm_vcpu *vcpu, u64 __user *uindices);
|
||||
unsigned long kvm_arm_num_coproc_regs(struct kvm_vcpu *vcpu);
|
||||
int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
|
||||
int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
|
||||
|
||||
int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
||||
int exception_index);
|
||||
|
||||
static inline void handle_exit_early(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
||||
int exception_index) {}
|
||||
|
||||
/* MMIO helpers */
|
||||
void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
|
||||
unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);
|
||||
|
||||
int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||
int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
||||
phys_addr_t fault_ipa);
|
||||
|
||||
static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
|
||||
unsigned long hyp_stack_ptr,
|
||||
unsigned long vector_ptr)
|
||||
{
|
||||
/*
|
||||
* Call initialization code, and switch to the full blown HYP
|
||||
* code. The init code doesn't need to preserve these
|
||||
* registers as r0-r3 are already callee saved according to
|
||||
* the AAPCS.
|
||||
* Note that we slightly misuse the prototype by casting the
|
||||
* stack pointer to a void *.
|
||||
|
||||
* The PGDs are always passed as the third argument, in order
|
||||
* to be passed into r2-r3 to the init code (yes, this is
|
||||
* compliant with the PCS!).
|
||||
*/
|
||||
|
||||
__kvm_call_hyp((void*)hyp_stack_ptr, vector_ptr, pgd_ptr);
|
||||
}
|
||||
|
||||
static inline void __cpu_init_stage2(void)
|
||||
{
|
||||
kvm_call_hyp(__init_stage2_translation);
|
||||
}
|
||||
|
||||
static inline int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_perf_init(void);
|
||||
int kvm_perf_teardown(void);
|
||||
|
||||
static inline long kvm_hypercall_pv_features(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return SMCCC_RET_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static inline gpa_t kvm_init_stolen_time(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return GPA_INVALID;
|
||||
}
|
||||
|
||||
static inline void kvm_update_stolen_time(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void kvm_arm_pvtime_vcpu_init(struct kvm_vcpu_arch *vcpu_arch)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool kvm_arm_is_pvtime_enabled(struct kvm_vcpu_arch *vcpu_arch)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void kvm_mmu_wp_memory_region(struct kvm *kvm, int slot);
|
||||
|
||||
struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
|
||||
|
||||
static inline bool kvm_arch_requires_vhe(void) { return false; }
|
||||
static inline void kvm_arch_hardware_unsetup(void) {}
|
||||
static inline void kvm_arch_sync_events(struct kvm *kvm) {}
|
||||
static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
|
||||
static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {}
|
||||
static inline void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu) {}
|
||||
|
||||
static inline void kvm_arm_init_debug(void) {}
|
||||
static inline void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) {}
|
||||
static inline void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) {}
|
||||
static inline void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu) {}
|
||||
|
||||
int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu,
|
||||
struct kvm_device_attr *attr);
|
||||
int kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu,
|
||||
struct kvm_device_attr *attr);
|
||||
int kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu,
|
||||
struct kvm_device_attr *attr);
|
||||
|
||||
/*
|
||||
* VFP/NEON switching is all done by the hyp switch code, so no need to
|
||||
* coordinate with host context handling for this state:
|
||||
*/
|
||||
static inline void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu) {}
|
||||
static inline void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu) {}
|
||||
static inline void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu) {}
|
||||
|
||||
static inline void kvm_vcpu_pmu_restore_guest(struct kvm_vcpu *vcpu) {}
|
||||
static inline void kvm_vcpu_pmu_restore_host(struct kvm_vcpu *vcpu) {}
|
||||
|
||||
#define KVM_BP_HARDEN_UNKNOWN -1
|
||||
#define KVM_BP_HARDEN_WA_NEEDED 0
|
||||
#define KVM_BP_HARDEN_NOT_REQUIRED 1
|
||||
|
||||
static inline int kvm_arm_harden_branch_predictor(void)
|
||||
{
|
||||
switch(read_cpuid_part()) {
|
||||
#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
|
||||
case ARM_CPU_PART_BRAHMA_B15:
|
||||
case ARM_CPU_PART_CORTEX_A12:
|
||||
case ARM_CPU_PART_CORTEX_A15:
|
||||
case ARM_CPU_PART_CORTEX_A17:
|
||||
return KVM_BP_HARDEN_WA_NEEDED;
|
||||
#endif
|
||||
case ARM_CPU_PART_CORTEX_A7:
|
||||
return KVM_BP_HARDEN_NOT_REQUIRED;
|
||||
default:
|
||||
return KVM_BP_HARDEN_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
#define KVM_SSBD_UNKNOWN -1
|
||||
#define KVM_SSBD_FORCE_DISABLE 0
|
||||
#define KVM_SSBD_KERNEL 1
|
||||
#define KVM_SSBD_FORCE_ENABLE 2
|
||||
#define KVM_SSBD_MITIGATED 3
|
||||
|
||||
static inline int kvm_arm_have_ssbd(void)
|
||||
{
|
||||
/* No way to detect it yet, pretend it is not there. */
|
||||
return KVM_SSBD_UNKNOWN;
|
||||
}
|
||||
|
||||
static inline void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu) {}
|
||||
static inline void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu) {}
|
||||
|
||||
#define __KVM_HAVE_ARCH_VM_ALLOC
|
||||
struct kvm *kvm_arch_alloc_vm(void);
|
||||
void kvm_arch_free_vm(struct kvm *kvm);
|
||||
|
||||
static inline int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type)
|
||||
{
|
||||
/*
|
||||
* On 32bit ARM, VMs get a static 40bit IPA stage2 setup,
|
||||
* so any non-zero value used as type is illegal.
|
||||
*/
|
||||
if (type)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* __ARM_KVM_HOST_H__ */
|
@ -1,127 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2015 - ARM Ltd
|
||||
* Author: Marc Zyngier <marc.zyngier@arm.com>
|
||||
*/
|
||||
|
||||
#ifndef __ARM_KVM_HYP_H__
|
||||
#define __ARM_KVM_HYP_H__
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <asm/cp15.h>
|
||||
#include <asm/kvm_arm.h>
|
||||
#include <asm/vfp.h>
|
||||
|
||||
#define __hyp_text __section(.hyp.text) notrace
|
||||
|
||||
#define __ACCESS_VFP(CRn) \
|
||||
"mrc", "mcr", __stringify(p10, 7, %0, CRn, cr0, 0), u32
|
||||
|
||||
#define write_special(v, r) \
|
||||
asm volatile("msr " __stringify(r) ", %0" : : "r" (v))
|
||||
#define read_special(r) ({ \
|
||||
u32 __val; \
|
||||
asm volatile("mrs %0, " __stringify(r) : "=r" (__val)); \
|
||||
__val; \
|
||||
})
|
||||
|
||||
#define TTBR0 __ACCESS_CP15_64(0, c2)
|
||||
#define TTBR1 __ACCESS_CP15_64(1, c2)
|
||||
#define VTTBR __ACCESS_CP15_64(6, c2)
|
||||
#define PAR __ACCESS_CP15_64(0, c7)
|
||||
#define CNTP_CVAL __ACCESS_CP15_64(2, c14)
|
||||
#define CNTV_CVAL __ACCESS_CP15_64(3, c14)
|
||||
#define CNTVOFF __ACCESS_CP15_64(4, c14)
|
||||
|
||||
#define MIDR __ACCESS_CP15(c0, 0, c0, 0)
|
||||
#define CSSELR __ACCESS_CP15(c0, 2, c0, 0)
|
||||
#define VPIDR __ACCESS_CP15(c0, 4, c0, 0)
|
||||
#define VMPIDR __ACCESS_CP15(c0, 4, c0, 5)
|
||||
#define SCTLR __ACCESS_CP15(c1, 0, c0, 0)
|
||||
#define CPACR __ACCESS_CP15(c1, 0, c0, 2)
|
||||
#define HCR __ACCESS_CP15(c1, 4, c1, 0)
|
||||
#define HDCR __ACCESS_CP15(c1, 4, c1, 1)
|
||||
#define HCPTR __ACCESS_CP15(c1, 4, c1, 2)
|
||||
#define HSTR __ACCESS_CP15(c1, 4, c1, 3)
|
||||
#define TTBCR __ACCESS_CP15(c2, 0, c0, 2)
|
||||
#define HTCR __ACCESS_CP15(c2, 4, c0, 2)
|
||||
#define VTCR __ACCESS_CP15(c2, 4, c1, 2)
|
||||
#define DACR __ACCESS_CP15(c3, 0, c0, 0)
|
||||
#define DFSR __ACCESS_CP15(c5, 0, c0, 0)
|
||||
#define IFSR __ACCESS_CP15(c5, 0, c0, 1)
|
||||
#define ADFSR __ACCESS_CP15(c5, 0, c1, 0)
|
||||
#define AIFSR __ACCESS_CP15(c5, 0, c1, 1)
|
||||
#define HSR __ACCESS_CP15(c5, 4, c2, 0)
|
||||
#define DFAR __ACCESS_CP15(c6, 0, c0, 0)
|
||||
#define IFAR __ACCESS_CP15(c6, 0, c0, 2)
|
||||
#define HDFAR __ACCESS_CP15(c6, 4, c0, 0)
|
||||
#define HIFAR __ACCESS_CP15(c6, 4, c0, 2)
|
||||
#define HPFAR __ACCESS_CP15(c6, 4, c0, 4)
|
||||
#define ICIALLUIS __ACCESS_CP15(c7, 0, c1, 0)
|
||||
#define BPIALLIS __ACCESS_CP15(c7, 0, c1, 6)
|
||||
#define ICIMVAU __ACCESS_CP15(c7, 0, c5, 1)
|
||||
#define ATS1CPR __ACCESS_CP15(c7, 0, c8, 0)
|
||||
#define TLBIALLIS __ACCESS_CP15(c8, 0, c3, 0)
|
||||
#define TLBIALL __ACCESS_CP15(c8, 0, c7, 0)
|
||||
#define TLBIALLNSNHIS __ACCESS_CP15(c8, 4, c3, 4)
|
||||
#define PRRR __ACCESS_CP15(c10, 0, c2, 0)
|
||||
#define NMRR __ACCESS_CP15(c10, 0, c2, 1)
|
||||
#define AMAIR0 __ACCESS_CP15(c10, 0, c3, 0)
|
||||
#define AMAIR1 __ACCESS_CP15(c10, 0, c3, 1)
|
||||
#define VBAR __ACCESS_CP15(c12, 0, c0, 0)
|
||||
#define CID __ACCESS_CP15(c13, 0, c0, 1)
|
||||
#define TID_URW __ACCESS_CP15(c13, 0, c0, 2)
|
||||
#define TID_URO __ACCESS_CP15(c13, 0, c0, 3)
|
||||
#define TID_PRIV __ACCESS_CP15(c13, 0, c0, 4)
|
||||
#define HTPIDR __ACCESS_CP15(c13, 4, c0, 2)
|
||||
#define CNTKCTL __ACCESS_CP15(c14, 0, c1, 0)
|
||||
#define CNTP_CTL __ACCESS_CP15(c14, 0, c2, 1)
|
||||
#define CNTV_CTL __ACCESS_CP15(c14, 0, c3, 1)
|
||||
#define CNTHCTL __ACCESS_CP15(c14, 4, c1, 0)
|
||||
|
||||
#define VFP_FPEXC __ACCESS_VFP(FPEXC)
|
||||
|
||||
/* AArch64 compatibility macros, only for the timer so far */
|
||||
#define read_sysreg_el0(r) read_sysreg(r##_EL0)
|
||||
#define write_sysreg_el0(v, r) write_sysreg(v, r##_EL0)
|
||||
|
||||
#define SYS_CNTP_CTL_EL0 CNTP_CTL
|
||||
#define SYS_CNTP_CVAL_EL0 CNTP_CVAL
|
||||
#define SYS_CNTV_CTL_EL0 CNTV_CTL
|
||||
#define SYS_CNTV_CVAL_EL0 CNTV_CVAL
|
||||
|
||||
#define cntvoff_el2 CNTVOFF
|
||||
#define cnthctl_el2 CNTHCTL
|
||||
|
||||
void __timer_enable_traps(struct kvm_vcpu *vcpu);
|
||||
void __timer_disable_traps(struct kvm_vcpu *vcpu);
|
||||
|
||||
void __vgic_v2_save_state(struct kvm_vcpu *vcpu);
|
||||
void __vgic_v2_restore_state(struct kvm_vcpu *vcpu);
|
||||
|
||||
void __sysreg_save_state(struct kvm_cpu_context *ctxt);
|
||||
void __sysreg_restore_state(struct kvm_cpu_context *ctxt);
|
||||
|
||||
void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
|
||||
void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
|
||||
void __vgic_v3_activate_traps(struct kvm_vcpu *vcpu);
|
||||
void __vgic_v3_deactivate_traps(struct kvm_vcpu *vcpu);
|
||||
void __vgic_v3_save_aprs(struct kvm_vcpu *vcpu);
|
||||
void __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu);
|
||||
|
||||
asmlinkage void __vfp_save_state(struct vfp_hard_struct *vfp);
|
||||
asmlinkage void __vfp_restore_state(struct vfp_hard_struct *vfp);
|
||||
static inline bool __vfp_enabled(void)
|
||||
{
|
||||
return !(read_sysreg(HCPTR) & (HCPTR_TCP(11) | HCPTR_TCP(10)));
|
||||
}
|
||||
|
||||
void __hyp_text __banked_save_state(struct kvm_cpu_context *ctxt);
|
||||
void __hyp_text __banked_restore_state(struct kvm_cpu_context *ctxt);
|
||||
|
||||
asmlinkage int __guest_enter(struct kvm_vcpu *vcpu,
|
||||
struct kvm_cpu_context *host);
|
||||
asmlinkage int __hyp_do_panic(const char *, int, u32);
|
||||
|
||||
#endif /* __ARM_KVM_HYP_H__ */
|
@ -1,435 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2012 - Virtual Open Systems and Columbia University
|
||||
* Author: Christoffer Dall <c.dall@virtualopensystems.com>
|
||||
*/
|
||||
|
||||
#ifndef __ARM_KVM_MMU_H__
|
||||
#define __ARM_KVM_MMU_H__
|
||||
|
||||
#include <asm/memory.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
/*
|
||||
* We directly use the kernel VA for the HYP, as we can directly share
|
||||
* the mapping (HTTBR "covers" TTBR1).
|
||||
*/
|
||||
#define kern_hyp_va(kva) (kva)
|
||||
|
||||
/* Contrary to arm64, there is no need to generate a PC-relative address */
|
||||
#define hyp_symbol_addr(s) \
|
||||
({ \
|
||||
typeof(s) *addr = &(s); \
|
||||
addr; \
|
||||
})
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <linux/highmem.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/kvm_arm.h>
|
||||
#include <asm/kvm_hyp.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/stage2_pgtable.h>
|
||||
|
||||
/* Ensure compatibility with arm64 */
|
||||
#define VA_BITS 32
|
||||
|
||||
#define kvm_phys_shift(kvm) KVM_PHYS_SHIFT
|
||||
#define kvm_phys_size(kvm) (1ULL << kvm_phys_shift(kvm))
|
||||
#define kvm_phys_mask(kvm) (kvm_phys_size(kvm) - 1ULL)
|
||||
#define kvm_vttbr_baddr_mask(kvm) VTTBR_BADDR_MASK
|
||||
|
||||
#define stage2_pgd_size(kvm) (PTRS_PER_S2_PGD * sizeof(pgd_t))
|
||||
|
||||
int create_hyp_mappings(void *from, void *to, pgprot_t prot);
|
||||
int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size,
|
||||
void __iomem **kaddr,
|
||||
void __iomem **haddr);
|
||||
int create_hyp_exec_mappings(phys_addr_t phys_addr, size_t size,
|
||||
void **haddr);
|
||||
void free_hyp_pgds(void);
|
||||
|
||||
void stage2_unmap_vm(struct kvm *kvm);
|
||||
int kvm_alloc_stage2_pgd(struct kvm *kvm);
|
||||
void kvm_free_stage2_pgd(struct kvm *kvm);
|
||||
int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
|
||||
phys_addr_t pa, unsigned long size, bool writable);
|
||||
|
||||
int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||
|
||||
void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu);
|
||||
|
||||
phys_addr_t kvm_mmu_get_httbr(void);
|
||||
phys_addr_t kvm_get_idmap_vector(void);
|
||||
int kvm_mmu_init(void);
|
||||
void kvm_clear_hyp_idmap(void);
|
||||
|
||||
#define kvm_mk_pmd(ptep) __pmd(__pa(ptep) | PMD_TYPE_TABLE)
|
||||
#define kvm_mk_pud(pmdp) __pud(__pa(pmdp) | PMD_TYPE_TABLE)
|
||||
#define kvm_mk_pgd(pudp) ({ BUILD_BUG(); 0; })
|
||||
|
||||
#define kvm_pfn_pte(pfn, prot) pfn_pte(pfn, prot)
|
||||
#define kvm_pfn_pmd(pfn, prot) pfn_pmd(pfn, prot)
|
||||
#define kvm_pfn_pud(pfn, prot) (__pud(0))
|
||||
|
||||
#define kvm_pud_pfn(pud) ({ WARN_ON(1); 0; })
|
||||
|
||||
|
||||
#define kvm_pmd_mkhuge(pmd) pmd_mkhuge(pmd)
|
||||
/* No support for pud hugepages */
|
||||
#define kvm_pud_mkhuge(pud) ( {WARN_ON(1); pud; })
|
||||
|
||||
/*
|
||||
* The following kvm_*pud*() functions are provided strictly to allow
|
||||
* sharing code with arm64. They should never be called in practice.
|
||||
*/
|
||||
static inline void kvm_set_s2pud_readonly(pud_t *pud)
|
||||
{
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
static inline bool kvm_s2pud_readonly(pud_t *pud)
|
||||
{
|
||||
WARN_ON(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void kvm_set_pud(pud_t *pud, pud_t new_pud)
|
||||
{
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
static inline pud_t kvm_s2pud_mkwrite(pud_t pud)
|
||||
{
|
||||
WARN_ON(1);
|
||||
return pud;
|
||||
}
|
||||
|
||||
static inline pud_t kvm_s2pud_mkexec(pud_t pud)
|
||||
{
|
||||
WARN_ON(1);
|
||||
return pud;
|
||||
}
|
||||
|
||||
static inline bool kvm_s2pud_exec(pud_t *pud)
|
||||
{
|
||||
WARN_ON(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline pud_t kvm_s2pud_mkyoung(pud_t pud)
|
||||
{
|
||||
BUG();
|
||||
return pud;
|
||||
}
|
||||
|
||||
static inline bool kvm_s2pud_young(pud_t pud)
|
||||
{
|
||||
WARN_ON(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline pte_t kvm_s2pte_mkwrite(pte_t pte)
|
||||
{
|
||||
pte_val(pte) |= L_PTE_S2_RDWR;
|
||||
return pte;
|
||||
}
|
||||
|
||||
static inline pmd_t kvm_s2pmd_mkwrite(pmd_t pmd)
|
||||
{
|
||||
pmd_val(pmd) |= L_PMD_S2_RDWR;
|
||||
return pmd;
|
||||
}
|
||||
|
||||
static inline pte_t kvm_s2pte_mkexec(pte_t pte)
|
||||
{
|
||||
pte_val(pte) &= ~L_PTE_XN;
|
||||
return pte;
|
||||
}
|
||||
|
||||
static inline pmd_t kvm_s2pmd_mkexec(pmd_t pmd)
|
||||
{
|
||||
pmd_val(pmd) &= ~PMD_SECT_XN;
|
||||
return pmd;
|
||||
}
|
||||
|
||||
static inline void kvm_set_s2pte_readonly(pte_t *pte)
|
||||
{
|
||||
pte_val(*pte) = (pte_val(*pte) & ~L_PTE_S2_RDWR) | L_PTE_S2_RDONLY;
|
||||
}
|
||||
|
||||
static inline bool kvm_s2pte_readonly(pte_t *pte)
|
||||
{
|
||||
return (pte_val(*pte) & L_PTE_S2_RDWR) == L_PTE_S2_RDONLY;
|
||||
}
|
||||
|
||||
static inline bool kvm_s2pte_exec(pte_t *pte)
|
||||
{
|
||||
return !(pte_val(*pte) & L_PTE_XN);
|
||||
}
|
||||
|
||||
static inline void kvm_set_s2pmd_readonly(pmd_t *pmd)
|
||||
{
|
||||
pmd_val(*pmd) = (pmd_val(*pmd) & ~L_PMD_S2_RDWR) | L_PMD_S2_RDONLY;
|
||||
}
|
||||
|
||||
static inline bool kvm_s2pmd_readonly(pmd_t *pmd)
|
||||
{
|
||||
return (pmd_val(*pmd) & L_PMD_S2_RDWR) == L_PMD_S2_RDONLY;
|
||||
}
|
||||
|
||||
static inline bool kvm_s2pmd_exec(pmd_t *pmd)
|
||||
{
|
||||
return !(pmd_val(*pmd) & PMD_SECT_XN);
|
||||
}
|
||||
|
||||
static inline bool kvm_page_empty(void *ptr)
|
||||
{
|
||||
struct page *ptr_page = virt_to_page(ptr);
|
||||
return page_count(ptr_page) == 1;
|
||||
}
|
||||
|
||||
#define kvm_pte_table_empty(kvm, ptep) kvm_page_empty(ptep)
|
||||
#define kvm_pmd_table_empty(kvm, pmdp) kvm_page_empty(pmdp)
|
||||
#define kvm_pud_table_empty(kvm, pudp) false
|
||||
|
||||
#define hyp_pte_table_empty(ptep) kvm_page_empty(ptep)
|
||||
#define hyp_pmd_table_empty(pmdp) kvm_page_empty(pmdp)
|
||||
#define hyp_pud_table_empty(pudp) false
|
||||
|
||||
struct kvm;
|
||||
|
||||
#define kvm_flush_dcache_to_poc(a,l) __cpuc_flush_dcache_area((a), (l))
|
||||
|
||||
static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return (vcpu_cp15(vcpu, c1_SCTLR) & 0b101) == 0b101;
|
||||
}
|
||||
|
||||
static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
|
||||
{
|
||||
/*
|
||||
* Clean the dcache to the Point of Coherency.
|
||||
*
|
||||
* We need to do this through a kernel mapping (using the
|
||||
* user-space mapping has proved to be the wrong
|
||||
* solution). For that, we need to kmap one page at a time,
|
||||
* and iterate over the range.
|
||||
*/
|
||||
|
||||
VM_BUG_ON(size & ~PAGE_MASK);
|
||||
|
||||
while (size) {
|
||||
void *va = kmap_atomic_pfn(pfn);
|
||||
|
||||
kvm_flush_dcache_to_poc(va, PAGE_SIZE);
|
||||
|
||||
size -= PAGE_SIZE;
|
||||
pfn++;
|
||||
|
||||
kunmap_atomic(va);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void __invalidate_icache_guest_page(kvm_pfn_t pfn,
|
||||
unsigned long size)
|
||||
{
|
||||
u32 iclsz;
|
||||
|
||||
/*
|
||||
* If we are going to insert an instruction page and the icache is
|
||||
* either VIPT or PIPT, there is a potential problem where the host
|
||||
* (or another VM) may have used the same page as this guest, and we
|
||||
* read incorrect data from the icache. If we're using a PIPT cache,
|
||||
* we can invalidate just that page, but if we are using a VIPT cache
|
||||
* we need to invalidate the entire icache - damn shame - as written
|
||||
* in the ARM ARM (DDI 0406C.b - Page B3-1393).
|
||||
*
|
||||
* VIVT caches are tagged using both the ASID and the VMID and doesn't
|
||||
* need any kind of flushing (DDI 0406C.b - Page B3-1392).
|
||||
*/
|
||||
|
||||
VM_BUG_ON(size & ~PAGE_MASK);
|
||||
|
||||
if (icache_is_vivt_asid_tagged())
|
||||
return;
|
||||
|
||||
if (!icache_is_pipt()) {
|
||||
/* any kind of VIPT cache */
|
||||
__flush_icache_all();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* CTR IminLine contains Log2 of the number of words in the
|
||||
* cache line, so we can get the number of words as
|
||||
* 2 << (IminLine - 1). To get the number of bytes, we
|
||||
* multiply by 4 (the number of bytes in a 32-bit word), and
|
||||
* get 4 << (IminLine).
|
||||
*/
|
||||
iclsz = 4 << (read_cpuid(CPUID_CACHETYPE) & 0xf);
|
||||
|
||||
while (size) {
|
||||
void *va = kmap_atomic_pfn(pfn);
|
||||
void *end = va + PAGE_SIZE;
|
||||
void *addr = va;
|
||||
|
||||
do {
|
||||
write_sysreg(addr, ICIMVAU);
|
||||
addr += iclsz;
|
||||
} while (addr < end);
|
||||
|
||||
dsb(ishst);
|
||||
isb();
|
||||
|
||||
size -= PAGE_SIZE;
|
||||
pfn++;
|
||||
|
||||
kunmap_atomic(va);
|
||||
}
|
||||
|
||||
/* Check if we need to invalidate the BTB */
|
||||
if ((read_cpuid_ext(CPUID_EXT_MMFR1) >> 28) != 4) {
|
||||
write_sysreg(0, BPIALLIS);
|
||||
dsb(ishst);
|
||||
isb();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void __kvm_flush_dcache_pte(pte_t pte)
|
||||
{
|
||||
void *va = kmap_atomic(pte_page(pte));
|
||||
|
||||
kvm_flush_dcache_to_poc(va, PAGE_SIZE);
|
||||
|
||||
kunmap_atomic(va);
|
||||
}
|
||||
|
||||
static inline void __kvm_flush_dcache_pmd(pmd_t pmd)
|
||||
{
|
||||
unsigned long size = PMD_SIZE;
|
||||
kvm_pfn_t pfn = pmd_pfn(pmd);
|
||||
|
||||
while (size) {
|
||||
void *va = kmap_atomic_pfn(pfn);
|
||||
|
||||
kvm_flush_dcache_to_poc(va, PAGE_SIZE);
|
||||
|
||||
pfn++;
|
||||
size -= PAGE_SIZE;
|
||||
|
||||
kunmap_atomic(va);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void __kvm_flush_dcache_pud(pud_t pud)
|
||||
{
|
||||
}
|
||||
|
||||
#define kvm_virt_to_phys(x) virt_to_idmap((unsigned long)(x))
|
||||
|
||||
void kvm_set_way_flush(struct kvm_vcpu *vcpu);
|
||||
void kvm_toggle_cache(struct kvm_vcpu *vcpu, bool was_enabled);
|
||||
|
||||
static inline bool __kvm_cpu_uses_extended_idmap(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline unsigned long __kvm_idmap_ptrs_per_pgd(void)
|
||||
{
|
||||
return PTRS_PER_PGD;
|
||||
}
|
||||
|
||||
static inline void __kvm_extend_hypmap(pgd_t *boot_hyp_pgd,
|
||||
pgd_t *hyp_pgd,
|
||||
pgd_t *merged_hyp_pgd,
|
||||
unsigned long hyp_idmap_start) { }
|
||||
|
||||
static inline unsigned int kvm_get_vmid_bits(void)
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
/*
|
||||
* We are not in the kvm->srcu critical section most of the time, so we take
|
||||
* the SRCU read lock here. Since we copy the data from the user page, we
|
||||
* can immediately drop the lock again.
|
||||
*/
|
||||
static inline int kvm_read_guest_lock(struct kvm *kvm,
|
||||
gpa_t gpa, void *data, unsigned long len)
|
||||
{
|
||||
int srcu_idx = srcu_read_lock(&kvm->srcu);
|
||||
int ret = kvm_read_guest(kvm, gpa, data, len);
|
||||
|
||||
srcu_read_unlock(&kvm->srcu, srcu_idx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int kvm_write_guest_lock(struct kvm *kvm, gpa_t gpa,
|
||||
const void *data, unsigned long len)
|
||||
{
|
||||
int srcu_idx = srcu_read_lock(&kvm->srcu);
|
||||
int ret = kvm_write_guest(kvm, gpa, data, len);
|
||||
|
||||
srcu_read_unlock(&kvm->srcu, srcu_idx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void *kvm_get_hyp_vector(void)
|
||||
{
|
||||
switch(read_cpuid_part()) {
|
||||
#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
|
||||
case ARM_CPU_PART_CORTEX_A12:
|
||||
case ARM_CPU_PART_CORTEX_A17:
|
||||
{
|
||||
extern char __kvm_hyp_vector_bp_inv[];
|
||||
return kvm_ksym_ref(__kvm_hyp_vector_bp_inv);
|
||||
}
|
||||
|
||||
case ARM_CPU_PART_BRAHMA_B15:
|
||||
case ARM_CPU_PART_CORTEX_A15:
|
||||
{
|
||||
extern char __kvm_hyp_vector_ic_inv[];
|
||||
return kvm_ksym_ref(__kvm_hyp_vector_ic_inv);
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
{
|
||||
extern char __kvm_hyp_vector[];
|
||||
return kvm_ksym_ref(__kvm_hyp_vector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline int kvm_map_vectors(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int hyp_map_aux_data(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define kvm_phys_to_vttbr(addr) (addr)
|
||||
|
||||
static inline void kvm_set_ipa_limit(void) {}
|
||||
|
||||
static __always_inline u64 kvm_get_vttbr(struct kvm *kvm)
|
||||
{
|
||||
struct kvm_vmid *vmid = &kvm->arch.vmid;
|
||||
u64 vmid_field, baddr;
|
||||
|
||||
baddr = kvm->arch.pgd_phys;
|
||||
vmid_field = (u64)vmid->vmid << VTTBR_VMID_SHIFT;
|
||||
return kvm_phys_to_vttbr(baddr) | vmid_field;
|
||||
}
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
#endif /* __ARM_KVM_MMU_H__ */
|
@ -1,14 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (C) 2018 - Arm Ltd */
|
||||
|
||||
#ifndef __ARM_KVM_RAS_H__
|
||||
#define __ARM_KVM_RAS_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
static inline int kvm_handle_guest_sea(phys_addr_t addr, unsigned int esr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* __ARM_KVM_RAS_H__ */
|
@ -104,26 +104,6 @@
|
||||
*/
|
||||
#define L_PGD_SWAPPER (_AT(pgdval_t, 1) << 55) /* swapper_pg_dir entry */
|
||||
|
||||
/*
|
||||
* 2nd stage PTE definitions for LPAE.
|
||||
*/
|
||||
#define L_PTE_S2_MT_UNCACHED (_AT(pteval_t, 0x0) << 2) /* strongly ordered */
|
||||
#define L_PTE_S2_MT_WRITETHROUGH (_AT(pteval_t, 0xa) << 2) /* normal inner write-through */
|
||||
#define L_PTE_S2_MT_WRITEBACK (_AT(pteval_t, 0xf) << 2) /* normal inner write-back */
|
||||
#define L_PTE_S2_MT_DEV_SHARED (_AT(pteval_t, 0x1) << 2) /* device */
|
||||
#define L_PTE_S2_MT_MASK (_AT(pteval_t, 0xf) << 2)
|
||||
|
||||
#define L_PTE_S2_RDONLY (_AT(pteval_t, 1) << 6) /* HAP[1] */
|
||||
#define L_PTE_S2_RDWR (_AT(pteval_t, 3) << 6) /* HAP[2:1] */
|
||||
|
||||
#define L_PMD_S2_RDONLY (_AT(pmdval_t, 1) << 6) /* HAP[1] */
|
||||
#define L_PMD_S2_RDWR (_AT(pmdval_t, 3) << 6) /* HAP[2:1] */
|
||||
|
||||
/*
|
||||
* Hyp-mode PL2 PTE definitions for LPAE.
|
||||
*/
|
||||
#define L_PTE_HYP L_PTE_USER
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#define pud_none(pud) (!pud_val(pud))
|
||||
|
@ -80,9 +80,6 @@ extern void __pgd_error(const char *file, int line, pgd_t);
|
||||
|
||||
extern pgprot_t pgprot_user;
|
||||
extern pgprot_t pgprot_kernel;
|
||||
extern pgprot_t pgprot_hyp_device;
|
||||
extern pgprot_t pgprot_s2;
|
||||
extern pgprot_t pgprot_s2_device;
|
||||
|
||||
#define _MOD_PROT(p, b) __pgprot(pgprot_val(p) | (b))
|
||||
|
||||
@ -95,12 +92,6 @@ extern pgprot_t pgprot_s2_device;
|
||||
#define PAGE_READONLY_EXEC _MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_RDONLY)
|
||||
#define PAGE_KERNEL _MOD_PROT(pgprot_kernel, L_PTE_XN)
|
||||
#define PAGE_KERNEL_EXEC pgprot_kernel
|
||||
#define PAGE_HYP _MOD_PROT(pgprot_kernel, L_PTE_HYP | L_PTE_XN)
|
||||
#define PAGE_HYP_EXEC _MOD_PROT(pgprot_kernel, L_PTE_HYP | L_PTE_RDONLY)
|
||||
#define PAGE_HYP_RO _MOD_PROT(pgprot_kernel, L_PTE_HYP | L_PTE_RDONLY | L_PTE_XN)
|
||||
#define PAGE_HYP_DEVICE _MOD_PROT(pgprot_hyp_device, L_PTE_HYP)
|
||||
#define PAGE_S2 _MOD_PROT(pgprot_s2, L_PTE_S2_RDONLY | L_PTE_XN)
|
||||
#define PAGE_S2_DEVICE _MOD_PROT(pgprot_s2_device, L_PTE_S2_RDONLY | L_PTE_XN)
|
||||
|
||||
#define __PAGE_NONE __pgprot(_L_PTE_DEFAULT | L_PTE_RDONLY | L_PTE_XN | L_PTE_NONE)
|
||||
#define __PAGE_SHARED __pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_XN)
|
||||
|
@ -10,8 +10,6 @@ extern char __idmap_text_start[];
|
||||
extern char __idmap_text_end[];
|
||||
extern char __entry_text_start[];
|
||||
extern char __entry_text_end[];
|
||||
extern char __hyp_idmap_text_start[];
|
||||
extern char __hyp_idmap_text_end[];
|
||||
|
||||
static inline bool in_entry_text(unsigned long addr)
|
||||
{
|
||||
@ -22,9 +20,7 @@ static inline bool in_entry_text(unsigned long addr)
|
||||
static inline bool in_idmap_text(unsigned long addr)
|
||||
{
|
||||
void *a = (void *)addr;
|
||||
return memory_contains(__idmap_text_start, __idmap_text_end, a, 1) ||
|
||||
memory_contains(__hyp_idmap_text_start, __hyp_idmap_text_end,
|
||||
a, 1);
|
||||
return memory_contains(__idmap_text_start, __idmap_text_end, a, 1);
|
||||
}
|
||||
|
||||
#endif /* _ASM_ARM_SECTIONS_H */
|
||||
|
@ -1,75 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2016 - ARM Ltd
|
||||
*
|
||||
* stage2 page table helpers
|
||||
*/
|
||||
|
||||
#ifndef __ARM_S2_PGTABLE_H_
|
||||
#define __ARM_S2_PGTABLE_H_
|
||||
|
||||
/*
|
||||
* kvm_mmu_cache_min_pages() is the number of pages required
|
||||
* to install a stage-2 translation. We pre-allocate the entry
|
||||
* level table at VM creation. Since we have a 3 level page-table,
|
||||
* we need only two pages to add a new mapping.
|
||||
*/
|
||||
#define kvm_mmu_cache_min_pages(kvm) 2
|
||||
|
||||
#define stage2_pgd_none(kvm, pgd) pgd_none(pgd)
|
||||
#define stage2_pgd_clear(kvm, pgd) pgd_clear(pgd)
|
||||
#define stage2_pgd_present(kvm, pgd) pgd_present(pgd)
|
||||
#define stage2_pgd_populate(kvm, pgd, pud) pgd_populate(NULL, pgd, pud)
|
||||
#define stage2_pud_offset(kvm, pgd, address) pud_offset(pgd, address)
|
||||
#define stage2_pud_free(kvm, pud) do { } while (0)
|
||||
|
||||
#define stage2_pud_none(kvm, pud) pud_none(pud)
|
||||
#define stage2_pud_clear(kvm, pud) pud_clear(pud)
|
||||
#define stage2_pud_present(kvm, pud) pud_present(pud)
|
||||
#define stage2_pud_populate(kvm, pud, pmd) pud_populate(NULL, pud, pmd)
|
||||
#define stage2_pmd_offset(kvm, pud, address) pmd_offset(pud, address)
|
||||
#define stage2_pmd_free(kvm, pmd) free_page((unsigned long)pmd)
|
||||
|
||||
#define stage2_pud_huge(kvm, pud) pud_huge(pud)
|
||||
|
||||
/* Open coded p*d_addr_end that can deal with 64bit addresses */
|
||||
static inline phys_addr_t
|
||||
stage2_pgd_addr_end(struct kvm *kvm, phys_addr_t addr, phys_addr_t end)
|
||||
{
|
||||
phys_addr_t boundary = (addr + PGDIR_SIZE) & PGDIR_MASK;
|
||||
|
||||
return (boundary - 1 < end - 1) ? boundary : end;
|
||||
}
|
||||
|
||||
#define stage2_pud_addr_end(kvm, addr, end) (end)
|
||||
|
||||
static inline phys_addr_t
|
||||
stage2_pmd_addr_end(struct kvm *kvm, phys_addr_t addr, phys_addr_t end)
|
||||
{
|
||||
phys_addr_t boundary = (addr + PMD_SIZE) & PMD_MASK;
|
||||
|
||||
return (boundary - 1 < end - 1) ? boundary : end;
|
||||
}
|
||||
|
||||
#define stage2_pgd_index(kvm, addr) pgd_index(addr)
|
||||
|
||||
#define stage2_pte_table_empty(kvm, ptep) kvm_page_empty(ptep)
|
||||
#define stage2_pmd_table_empty(kvm, pmdp) kvm_page_empty(pmdp)
|
||||
#define stage2_pud_table_empty(kvm, pudp) false
|
||||
|
||||
static inline bool kvm_stage2_has_pud(struct kvm *kvm)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#define S2_PMD_MASK PMD_MASK
|
||||
#define S2_PMD_SIZE PMD_SIZE
|
||||
#define S2_PUD_MASK PUD_MASK
|
||||
#define S2_PUD_SIZE PUD_SIZE
|
||||
|
||||
static inline bool kvm_stage2_has_pmd(struct kvm *kvm)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* __ARM_S2_PGTABLE_H_ */
|
@ -39,8 +39,6 @@ static inline void sync_boot_mode(void)
|
||||
sync_cache_r(&__boot_cpu_mode);
|
||||
}
|
||||
|
||||
void __hyp_set_vectors(unsigned long phys_vector_base);
|
||||
void __hyp_reset_vectors(void);
|
||||
#else
|
||||
#define __boot_cpu_mode (SVC_MODE)
|
||||
#define sync_boot_mode()
|
||||
@ -67,18 +65,6 @@ static inline bool is_kernel_in_hyp_mode(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool has_vhe(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The section containing the hypervisor idmap text */
|
||||
extern char __hyp_idmap_text_start[];
|
||||
extern char __hyp_idmap_text_end[];
|
||||
|
||||
/* The section containing the hypervisor text */
|
||||
extern char __hyp_text_start[];
|
||||
extern char __hyp_text_end[];
|
||||
#endif
|
||||
|
||||
#else
|
||||
@ -87,9 +73,6 @@ extern char __hyp_text_end[];
|
||||
|
||||
#define HVC_SET_VECTORS 0
|
||||
#define HVC_SOFT_RESTART 1
|
||||
#define HVC_RESET_VECTORS 2
|
||||
|
||||
#define HVC_STUB_HCALL_NR 3
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
|
@ -1,314 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (C) 2012 - Virtual Open Systems and Columbia University
|
||||
* Author: Christoffer Dall <c.dall@virtualopensystems.com>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __ARM_KVM_H__
|
||||
#define __ARM_KVM_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/psci.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
#define __KVM_HAVE_GUEST_DEBUG
|
||||
#define __KVM_HAVE_IRQ_LINE
|
||||
#define __KVM_HAVE_READONLY_MEM
|
||||
#define __KVM_HAVE_VCPU_EVENTS
|
||||
|
||||
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
|
||||
|
||||
#define KVM_REG_SIZE(id) \
|
||||
(1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
|
||||
|
||||
/* Valid for svc_regs, abt_regs, und_regs, irq_regs in struct kvm_regs */
|
||||
#define KVM_ARM_SVC_sp svc_regs[0]
|
||||
#define KVM_ARM_SVC_lr svc_regs[1]
|
||||
#define KVM_ARM_SVC_spsr svc_regs[2]
|
||||
#define KVM_ARM_ABT_sp abt_regs[0]
|
||||
#define KVM_ARM_ABT_lr abt_regs[1]
|
||||
#define KVM_ARM_ABT_spsr abt_regs[2]
|
||||
#define KVM_ARM_UND_sp und_regs[0]
|
||||
#define KVM_ARM_UND_lr und_regs[1]
|
||||
#define KVM_ARM_UND_spsr und_regs[2]
|
||||
#define KVM_ARM_IRQ_sp irq_regs[0]
|
||||
#define KVM_ARM_IRQ_lr irq_regs[1]
|
||||
#define KVM_ARM_IRQ_spsr irq_regs[2]
|
||||
|
||||
/* Valid only for fiq_regs in struct kvm_regs */
|
||||
#define KVM_ARM_FIQ_r8 fiq_regs[0]
|
||||
#define KVM_ARM_FIQ_r9 fiq_regs[1]
|
||||
#define KVM_ARM_FIQ_r10 fiq_regs[2]
|
||||
#define KVM_ARM_FIQ_fp fiq_regs[3]
|
||||
#define KVM_ARM_FIQ_ip fiq_regs[4]
|
||||
#define KVM_ARM_FIQ_sp fiq_regs[5]
|
||||
#define KVM_ARM_FIQ_lr fiq_regs[6]
|
||||
#define KVM_ARM_FIQ_spsr fiq_regs[7]
|
||||
|
||||
struct kvm_regs {
|
||||
struct pt_regs usr_regs; /* R0_usr - R14_usr, PC, CPSR */
|
||||
unsigned long svc_regs[3]; /* SP_svc, LR_svc, SPSR_svc */
|
||||
unsigned long abt_regs[3]; /* SP_abt, LR_abt, SPSR_abt */
|
||||
unsigned long und_regs[3]; /* SP_und, LR_und, SPSR_und */
|
||||
unsigned long irq_regs[3]; /* SP_irq, LR_irq, SPSR_irq */
|
||||
unsigned long fiq_regs[8]; /* R8_fiq - R14_fiq, SPSR_fiq */
|
||||
};
|
||||
|
||||
/* Supported Processor Types */
|
||||
#define KVM_ARM_TARGET_CORTEX_A15 0
|
||||
#define KVM_ARM_TARGET_CORTEX_A7 1
|
||||
#define KVM_ARM_NUM_TARGETS 2
|
||||
|
||||
/* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */
|
||||
#define KVM_ARM_DEVICE_TYPE_SHIFT 0
|
||||
#define KVM_ARM_DEVICE_TYPE_MASK (0xffff << KVM_ARM_DEVICE_TYPE_SHIFT)
|
||||
#define KVM_ARM_DEVICE_ID_SHIFT 16
|
||||
#define KVM_ARM_DEVICE_ID_MASK (0xffff << KVM_ARM_DEVICE_ID_SHIFT)
|
||||
|
||||
/* Supported device IDs */
|
||||
#define KVM_ARM_DEVICE_VGIC_V2 0
|
||||
|
||||
/* Supported VGIC address types */
|
||||
#define KVM_VGIC_V2_ADDR_TYPE_DIST 0
|
||||
#define KVM_VGIC_V2_ADDR_TYPE_CPU 1
|
||||
|
||||
#define KVM_VGIC_V2_DIST_SIZE 0x1000
|
||||
#define KVM_VGIC_V2_CPU_SIZE 0x2000
|
||||
|
||||
/* Supported VGICv3 address types */
|
||||
#define KVM_VGIC_V3_ADDR_TYPE_DIST 2
|
||||
#define KVM_VGIC_V3_ADDR_TYPE_REDIST 3
|
||||
#define KVM_VGIC_ITS_ADDR_TYPE 4
|
||||
#define KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION 5
|
||||
|
||||
#define KVM_VGIC_V3_DIST_SIZE SZ_64K
|
||||
#define KVM_VGIC_V3_REDIST_SIZE (2 * SZ_64K)
|
||||
#define KVM_VGIC_V3_ITS_SIZE (2 * SZ_64K)
|
||||
|
||||
#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */
|
||||
#define KVM_ARM_VCPU_PSCI_0_2 1 /* CPU uses PSCI v0.2 */
|
||||
|
||||
struct kvm_vcpu_init {
|
||||
__u32 target;
|
||||
__u32 features[7];
|
||||
};
|
||||
|
||||
struct kvm_sregs {
|
||||
};
|
||||
|
||||
struct kvm_fpu {
|
||||
};
|
||||
|
||||
struct kvm_guest_debug_arch {
|
||||
};
|
||||
|
||||
struct kvm_debug_exit_arch {
|
||||
};
|
||||
|
||||
struct kvm_sync_regs {
|
||||
/* Used with KVM_CAP_ARM_USER_IRQ */
|
||||
__u64 device_irq_level;
|
||||
};
|
||||
|
||||
struct kvm_arch_memory_slot {
|
||||
};
|
||||
|
||||
/* for KVM_GET/SET_VCPU_EVENTS */
|
||||
struct kvm_vcpu_events {
|
||||
struct {
|
||||
__u8 serror_pending;
|
||||
__u8 serror_has_esr;
|
||||
__u8 ext_dabt_pending;
|
||||
/* Align it to 8 bytes */
|
||||
__u8 pad[5];
|
||||
__u64 serror_esr;
|
||||
} exception;
|
||||
__u32 reserved[12];
|
||||
};
|
||||
|
||||
/* If you need to interpret the index values, here is the key: */
|
||||
#define KVM_REG_ARM_COPROC_MASK 0x000000000FFF0000
|
||||
#define KVM_REG_ARM_COPROC_SHIFT 16
|
||||
#define KVM_REG_ARM_32_OPC2_MASK 0x0000000000000007
|
||||
#define KVM_REG_ARM_32_OPC2_SHIFT 0
|
||||
#define KVM_REG_ARM_OPC1_MASK 0x0000000000000078
|
||||
#define KVM_REG_ARM_OPC1_SHIFT 3
|
||||
#define KVM_REG_ARM_CRM_MASK 0x0000000000000780
|
||||
#define KVM_REG_ARM_CRM_SHIFT 7
|
||||
#define KVM_REG_ARM_32_CRN_MASK 0x0000000000007800
|
||||
#define KVM_REG_ARM_32_CRN_SHIFT 11
|
||||
/*
|
||||
* For KVM currently all guest registers are nonsecure, but we reserve a bit
|
||||
* in the encoding to distinguish secure from nonsecure for AArch32 system
|
||||
* registers that are banked by security. This is 1 for the secure banked
|
||||
* register, and 0 for the nonsecure banked register or if the register is
|
||||
* not banked by security.
|
||||
*/
|
||||
#define KVM_REG_ARM_SECURE_MASK 0x0000000010000000
|
||||
#define KVM_REG_ARM_SECURE_SHIFT 28
|
||||
|
||||
#define ARM_CP15_REG_SHIFT_MASK(x,n) \
|
||||
(((x) << KVM_REG_ARM_ ## n ## _SHIFT) & KVM_REG_ARM_ ## n ## _MASK)
|
||||
|
||||
#define __ARM_CP15_REG(op1,crn,crm,op2) \
|
||||
(KVM_REG_ARM | (15 << KVM_REG_ARM_COPROC_SHIFT) | \
|
||||
ARM_CP15_REG_SHIFT_MASK(op1, OPC1) | \
|
||||
ARM_CP15_REG_SHIFT_MASK(crn, 32_CRN) | \
|
||||
ARM_CP15_REG_SHIFT_MASK(crm, CRM) | \
|
||||
ARM_CP15_REG_SHIFT_MASK(op2, 32_OPC2))
|
||||
|
||||
#define ARM_CP15_REG32(...) (__ARM_CP15_REG(__VA_ARGS__) | KVM_REG_SIZE_U32)
|
||||
|
||||
#define __ARM_CP15_REG64(op1,crm) \
|
||||
(__ARM_CP15_REG(op1, 0, crm, 0) | KVM_REG_SIZE_U64)
|
||||
#define ARM_CP15_REG64(...) __ARM_CP15_REG64(__VA_ARGS__)
|
||||
|
||||
/* PL1 Physical Timer Registers */
|
||||
#define KVM_REG_ARM_PTIMER_CTL ARM_CP15_REG32(0, 14, 2, 1)
|
||||
#define KVM_REG_ARM_PTIMER_CNT ARM_CP15_REG64(0, 14)
|
||||
#define KVM_REG_ARM_PTIMER_CVAL ARM_CP15_REG64(2, 14)
|
||||
|
||||
/* Virtual Timer Registers */
|
||||
#define KVM_REG_ARM_TIMER_CTL ARM_CP15_REG32(0, 14, 3, 1)
|
||||
#define KVM_REG_ARM_TIMER_CNT ARM_CP15_REG64(1, 14)
|
||||
#define KVM_REG_ARM_TIMER_CVAL ARM_CP15_REG64(3, 14)
|
||||
|
||||
/* Normal registers are mapped as coprocessor 16. */
|
||||
#define KVM_REG_ARM_CORE (0x0010 << KVM_REG_ARM_COPROC_SHIFT)
|
||||
#define KVM_REG_ARM_CORE_REG(name) (offsetof(struct kvm_regs, name) / 4)
|
||||
|
||||
/* Some registers need more space to represent values. */
|
||||
#define KVM_REG_ARM_DEMUX (0x0011 << KVM_REG_ARM_COPROC_SHIFT)
|
||||
#define KVM_REG_ARM_DEMUX_ID_MASK 0x000000000000FF00
|
||||
#define KVM_REG_ARM_DEMUX_ID_SHIFT 8
|
||||
#define KVM_REG_ARM_DEMUX_ID_CCSIDR (0x00 << KVM_REG_ARM_DEMUX_ID_SHIFT)
|
||||
#define KVM_REG_ARM_DEMUX_VAL_MASK 0x00000000000000FF
|
||||
#define KVM_REG_ARM_DEMUX_VAL_SHIFT 0
|
||||
|
||||
/* VFP registers: we could overload CP10 like ARM does, but that's ugly. */
|
||||
#define KVM_REG_ARM_VFP (0x0012 << KVM_REG_ARM_COPROC_SHIFT)
|
||||
#define KVM_REG_ARM_VFP_MASK 0x000000000000FFFF
|
||||
#define KVM_REG_ARM_VFP_BASE_REG 0x0
|
||||
#define KVM_REG_ARM_VFP_FPSID 0x1000
|
||||
#define KVM_REG_ARM_VFP_FPSCR 0x1001
|
||||
#define KVM_REG_ARM_VFP_MVFR1 0x1006
|
||||
#define KVM_REG_ARM_VFP_MVFR0 0x1007
|
||||
#define KVM_REG_ARM_VFP_FPEXC 0x1008
|
||||
#define KVM_REG_ARM_VFP_FPINST 0x1009
|
||||
#define KVM_REG_ARM_VFP_FPINST2 0x100A
|
||||
|
||||
/* KVM-as-firmware specific pseudo-registers */
|
||||
#define KVM_REG_ARM_FW (0x0014 << KVM_REG_ARM_COPROC_SHIFT)
|
||||
#define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM | KVM_REG_SIZE_U64 | \
|
||||
KVM_REG_ARM_FW | ((r) & 0xffff))
|
||||
#define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0)
|
||||
#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1 KVM_REG_ARM_FW_REG(1)
|
||||
/* Higher values mean better protection. */
|
||||
#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL 0
|
||||
#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL 1
|
||||
#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED 2
|
||||
#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2 KVM_REG_ARM_FW_REG(2)
|
||||
/* Higher values mean better protection. */
|
||||
#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL 0
|
||||
#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN 1
|
||||
#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL 2
|
||||
#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED 3
|
||||
#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED (1U << 4)
|
||||
|
||||
/* Device Control API: ARM VGIC */
|
||||
#define KVM_DEV_ARM_VGIC_GRP_ADDR 0
|
||||
#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1
|
||||
#define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2
|
||||
#define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32
|
||||
#define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
|
||||
#define KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT 32
|
||||
#define KVM_DEV_ARM_VGIC_V3_MPIDR_MASK \
|
||||
(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
|
||||
#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0
|
||||
#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
|
||||
#define KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK (0xffff)
|
||||
#define KVM_DEV_ARM_VGIC_GRP_NR_IRQS 3
|
||||
#define KVM_DEV_ARM_VGIC_GRP_CTRL 4
|
||||
#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
|
||||
#define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6
|
||||
#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
|
||||
#define KVM_DEV_ARM_VGIC_GRP_ITS_REGS 8
|
||||
#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10
|
||||
#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
|
||||
(0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
|
||||
#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff
|
||||
#define VGIC_LEVEL_INFO_LINE_LEVEL 0
|
||||
|
||||
/* Device Control API on vcpu fd */
|
||||
#define KVM_ARM_VCPU_PMU_V3_CTRL 0
|
||||
#define KVM_ARM_VCPU_PMU_V3_IRQ 0
|
||||
#define KVM_ARM_VCPU_PMU_V3_INIT 1
|
||||
#define KVM_ARM_VCPU_TIMER_CTRL 1
|
||||
#define KVM_ARM_VCPU_TIMER_IRQ_VTIMER 0
|
||||
#define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1
|
||||
|
||||
#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
|
||||
#define KVM_DEV_ARM_ITS_SAVE_TABLES 1
|
||||
#define KVM_DEV_ARM_ITS_RESTORE_TABLES 2
|
||||
#define KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES 3
|
||||
#define KVM_DEV_ARM_ITS_CTRL_RESET 4
|
||||
|
||||
/* KVM_IRQ_LINE irq field index values */
|
||||
#define KVM_ARM_IRQ_VCPU2_SHIFT 28
|
||||
#define KVM_ARM_IRQ_VCPU2_MASK 0xf
|
||||
#define KVM_ARM_IRQ_TYPE_SHIFT 24
|
||||
#define KVM_ARM_IRQ_TYPE_MASK 0xf
|
||||
#define KVM_ARM_IRQ_VCPU_SHIFT 16
|
||||
#define KVM_ARM_IRQ_VCPU_MASK 0xff
|
||||
#define KVM_ARM_IRQ_NUM_SHIFT 0
|
||||
#define KVM_ARM_IRQ_NUM_MASK 0xffff
|
||||
|
||||
/* irq_type field */
|
||||
#define KVM_ARM_IRQ_TYPE_CPU 0
|
||||
#define KVM_ARM_IRQ_TYPE_SPI 1
|
||||
#define KVM_ARM_IRQ_TYPE_PPI 2
|
||||
|
||||
/* out-of-kernel GIC cpu interrupt injection irq_number field */
|
||||
#define KVM_ARM_IRQ_CPU_IRQ 0
|
||||
#define KVM_ARM_IRQ_CPU_FIQ 1
|
||||
|
||||
/*
|
||||
* This used to hold the highest supported SPI, but it is now obsolete
|
||||
* and only here to provide source code level compatibility with older
|
||||
* userland. The highest SPI number can be set via KVM_DEV_ARM_VGIC_GRP_NR_IRQS.
|
||||
*/
|
||||
#ifndef __KERNEL__
|
||||
#define KVM_ARM_IRQ_GIC_MAX 127
|
||||
#endif
|
||||
|
||||
/* One single KVM irqchip, ie. the VGIC */
|
||||
#define KVM_NR_IRQCHIPS 1
|
||||
|
||||
/* PSCI interface */
|
||||
#define KVM_PSCI_FN_BASE 0x95c1ba5e
|
||||
#define KVM_PSCI_FN(n) (KVM_PSCI_FN_BASE + (n))
|
||||
|
||||
#define KVM_PSCI_FN_CPU_SUSPEND KVM_PSCI_FN(0)
|
||||
#define KVM_PSCI_FN_CPU_OFF KVM_PSCI_FN(1)
|
||||
#define KVM_PSCI_FN_CPU_ON KVM_PSCI_FN(2)
|
||||
#define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3)
|
||||
|
||||
#define KVM_PSCI_RET_SUCCESS PSCI_RET_SUCCESS
|
||||
#define KVM_PSCI_RET_NI PSCI_RET_NOT_SUPPORTED
|
||||
#define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS
|
||||
#define KVM_PSCI_RET_DENIED PSCI_RET_DENIED
|
||||
|
||||
#endif /* __ARM_KVM_H__ */
|
@ -11,9 +11,6 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#ifdef CONFIG_KVM_ARM_HOST
|
||||
#include <linux/kvm_host.h>
|
||||
#endif
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/glue-df.h>
|
||||
#include <asm/glue-pf.h>
|
||||
@ -167,14 +164,6 @@ int main(void)
|
||||
DEFINE(CACHE_WRITEBACK_ORDER, __CACHE_WRITEBACK_ORDER);
|
||||
DEFINE(CACHE_WRITEBACK_GRANULE, __CACHE_WRITEBACK_GRANULE);
|
||||
BLANK();
|
||||
#ifdef CONFIG_KVM_ARM_HOST
|
||||
DEFINE(VCPU_GUEST_CTXT, offsetof(struct kvm_vcpu, arch.ctxt));
|
||||
DEFINE(VCPU_HOST_CTXT, offsetof(struct kvm_vcpu, arch.host_cpu_context));
|
||||
DEFINE(CPU_CTXT_VFP, offsetof(struct kvm_cpu_context, vfp));
|
||||
DEFINE(CPU_CTXT_GP_REGS, offsetof(struct kvm_cpu_context, gp_regs));
|
||||
DEFINE(GP_REGS_USR, offsetof(struct kvm_regs, usr_regs));
|
||||
#endif
|
||||
BLANK();
|
||||
#ifdef CONFIG_VDSO
|
||||
DEFINE(VDSO_DATA_SIZE, sizeof(union vdso_data_store));
|
||||
#endif
|
||||
|
@ -189,19 +189,19 @@ ARM_BE8(orr r7, r7, #(1 << 25)) @ HSCTLR.EE
|
||||
ENDPROC(__hyp_stub_install_secondary)
|
||||
|
||||
__hyp_stub_do_trap:
|
||||
#ifdef ZIMAGE
|
||||
teq r0, #HVC_SET_VECTORS
|
||||
bne 1f
|
||||
/* Only the ZIMAGE stubs can change the HYP vectors */
|
||||
mcr p15, 4, r1, c12, c0, 0 @ set HVBAR
|
||||
b __hyp_stub_exit
|
||||
#endif
|
||||
|
||||
1: teq r0, #HVC_SOFT_RESTART
|
||||
bne 1f
|
||||
bne 2f
|
||||
bx r1
|
||||
|
||||
1: teq r0, #HVC_RESET_VECTORS
|
||||
beq __hyp_stub_exit
|
||||
|
||||
ldr r0, =HVC_STUB_ERR
|
||||
2: ldr r0, =HVC_STUB_ERR
|
||||
__ERET
|
||||
|
||||
__hyp_stub_exit:
|
||||
@ -210,26 +210,9 @@ __hyp_stub_exit:
|
||||
ENDPROC(__hyp_stub_do_trap)
|
||||
|
||||
/*
|
||||
* __hyp_set_vectors: Call this after boot to set the initial hypervisor
|
||||
* vectors as part of hypervisor installation. On an SMP system, this should
|
||||
* be called on each CPU.
|
||||
*
|
||||
* r0 must be the physical address of the new vector table (which must lie in
|
||||
* the bottom 4GB of physical address space.
|
||||
*
|
||||
* r0 must be 32-byte aligned.
|
||||
*
|
||||
* Before calling this, you must check that the stub hypervisor is installed
|
||||
* everywhere, by waiting for any secondary CPUs to be brought up and then
|
||||
* checking that BOOT_CPU_MODE_HAVE_HYP(__boot_cpu_mode) is true.
|
||||
*
|
||||
* If not, there is a pre-existing hypervisor, some CPUs failed to boot, or
|
||||
* something else went wrong... in such cases, trying to install a new
|
||||
* hypervisor is unlikely to work as desired.
|
||||
*
|
||||
* When you call into your shiny new hypervisor, sp_hyp will contain junk,
|
||||
* so you will need to set that to something sensible at the new hypervisor's
|
||||
* initialisation entry point.
|
||||
* __hyp_set_vectors is only used when ZIMAGE must bounce between HYP
|
||||
* and SVC. For the kernel itself, the vectors are set once and for
|
||||
* all by the stubs.
|
||||
*/
|
||||
ENTRY(__hyp_set_vectors)
|
||||
mov r1, r0
|
||||
@ -245,12 +228,6 @@ ENTRY(__hyp_soft_restart)
|
||||
ret lr
|
||||
ENDPROC(__hyp_soft_restart)
|
||||
|
||||
ENTRY(__hyp_reset_vectors)
|
||||
mov r0, #HVC_RESET_VECTORS
|
||||
__HVC(0)
|
||||
ret lr
|
||||
ENDPROC(__hyp_reset_vectors)
|
||||
|
||||
#ifndef ZIMAGE
|
||||
.align 2
|
||||
.L__boot_cpu_mode_offset:
|
||||
|
@ -162,14 +162,6 @@ SECTIONS
|
||||
ASSERT((__proc_info_end - __proc_info_begin), "missing CPU support")
|
||||
ASSERT((__arch_info_end - __arch_info_begin), "no machine record defined")
|
||||
|
||||
/*
|
||||
* The HYP init code can't be more than a page long,
|
||||
* and should not cross a page boundary.
|
||||
* The above comment applies as well.
|
||||
*/
|
||||
ASSERT(__hyp_idmap_text_end - (__hyp_idmap_text_start & PAGE_MASK) <= PAGE_SIZE,
|
||||
"HYP init code too big or misaligned")
|
||||
|
||||
#ifdef CONFIG_XIP_DEFLATED_DATA
|
||||
/*
|
||||
* The .bss is used as a stack area for __inflate_kernel_data() whose stack
|
||||
|
@ -170,12 +170,4 @@ __start_rodata_section_aligned = ALIGN(__start_rodata, 1 << SECTION_SHIFT);
|
||||
ASSERT((__proc_info_end - __proc_info_begin), "missing CPU support")
|
||||
ASSERT((__arch_info_end - __arch_info_begin), "no machine record defined")
|
||||
|
||||
/*
|
||||
* The HYP init code can't be more than a page long,
|
||||
* and should not cross a page boundary.
|
||||
* The above comment applies as well.
|
||||
*/
|
||||
ASSERT(__hyp_idmap_text_end - (__hyp_idmap_text_start & PAGE_MASK) <= PAGE_SIZE,
|
||||
"HYP init code too big or misaligned")
|
||||
|
||||
#endif /* CONFIG_XIP_KERNEL */
|
||||
|
@ -31,20 +31,11 @@
|
||||
*(.proc.info.init) \
|
||||
__proc_info_end = .;
|
||||
|
||||
#define HYPERVISOR_TEXT \
|
||||
__hyp_text_start = .; \
|
||||
*(.hyp.text) \
|
||||
__hyp_text_end = .;
|
||||
|
||||
#define IDMAP_TEXT \
|
||||
ALIGN_FUNCTION(); \
|
||||
__idmap_text_start = .; \
|
||||
*(.idmap.text) \
|
||||
__idmap_text_end = .; \
|
||||
. = ALIGN(PAGE_SIZE); \
|
||||
__hyp_idmap_text_start = .; \
|
||||
*(.hyp.idmap.text) \
|
||||
__hyp_idmap_text_end = .;
|
||||
|
||||
#define ARM_DISCARD \
|
||||
*(.ARM.exidx.exit.text) \
|
||||
@ -72,7 +63,6 @@
|
||||
SCHED_TEXT \
|
||||
CPUIDLE_TEXT \
|
||||
LOCK_TEXT \
|
||||
HYPERVISOR_TEXT \
|
||||
KPROBES_TEXT \
|
||||
*(.gnu.warning) \
|
||||
*(.glue_7) \
|
||||
|
@ -1,59 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# KVM configuration
|
||||
#
|
||||
|
||||
source "virt/kvm/Kconfig"
|
||||
source "virt/lib/Kconfig"
|
||||
|
||||
menuconfig VIRTUALIZATION
|
||||
bool "Virtualization"
|
||||
---help---
|
||||
Say Y here to get to see options for using your Linux host to run
|
||||
other operating systems inside virtual machines (guests).
|
||||
This option alone does not add any kernel code.
|
||||
|
||||
If you say N, all options in this submenu will be skipped and
|
||||
disabled.
|
||||
|
||||
if VIRTUALIZATION
|
||||
|
||||
config KVM
|
||||
bool "Kernel-based Virtual Machine (KVM) support"
|
||||
depends on MMU && OF
|
||||
select PREEMPT_NOTIFIERS
|
||||
select ARM_GIC
|
||||
select ARM_GIC_V3
|
||||
select ARM_GIC_V3_ITS
|
||||
select HAVE_KVM_CPU_RELAX_INTERCEPT
|
||||
select HAVE_KVM_ARCH_TLB_FLUSH_ALL
|
||||
select KVM_MMIO
|
||||
select KVM_ARM_HOST
|
||||
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
|
||||
select SRCU
|
||||
select MMU_NOTIFIER
|
||||
select KVM_VFIO
|
||||
select HAVE_KVM_EVENTFD
|
||||
select HAVE_KVM_IRQFD
|
||||
select HAVE_KVM_IRQCHIP
|
||||
select HAVE_KVM_IRQ_ROUTING
|
||||
select HAVE_KVM_MSI
|
||||
select IRQ_BYPASS_MANAGER
|
||||
select HAVE_KVM_IRQ_BYPASS
|
||||
depends on ARM_VIRT_EXT && ARM_LPAE && ARM_ARCH_TIMER
|
||||
---help---
|
||||
Support hosting virtualized guest machines.
|
||||
|
||||
This module provides access to the hardware capabilities through
|
||||
a character device node named /dev/kvm.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config KVM_ARM_HOST
|
||||
bool
|
||||
---help---
|
||||
Provides host support for ARM processors.
|
||||
|
||||
source "drivers/vhost/Kconfig"
|
||||
|
||||
endif # VIRTUALIZATION
|
@ -1,43 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for Kernel-based Virtual Machine module
|
||||
#
|
||||
|
||||
plus_virt := $(call as-instr,.arch_extension virt,+virt)
|
||||
ifeq ($(plus_virt),+virt)
|
||||
plus_virt_def := -DREQUIRES_VIRT=1
|
||||
endif
|
||||
|
||||
KVM := ../../../virt/kvm
|
||||
|
||||
ccflags-y += -I $(srctree)/$(src) -I $(srctree)/virt/kvm/arm/vgic
|
||||
CFLAGS_$(KVM)/arm/arm.o := $(plus_virt_def)
|
||||
|
||||
AFLAGS_init.o := -Wa,-march=armv7-a$(plus_virt)
|
||||
AFLAGS_interrupts.o := -Wa,-march=armv7-a$(plus_virt)
|
||||
|
||||
kvm-arm-y = $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/eventfd.o $(KVM)/vfio.o
|
||||
|
||||
obj-$(CONFIG_KVM_ARM_HOST) += hyp/
|
||||
|
||||
obj-y += kvm-arm.o init.o interrupts.o
|
||||
obj-y += handle_exit.o guest.o emulate.o reset.o
|
||||
obj-y += coproc.o coproc_a15.o coproc_a7.o vgic-v3-coproc.o
|
||||
obj-y += $(KVM)/arm/arm.o $(KVM)/arm/mmu.o $(KVM)/arm/mmio.o
|
||||
obj-y += $(KVM)/arm/psci.o $(KVM)/arm/perf.o $(KVM)/arm/hypercalls.o
|
||||
obj-y += $(KVM)/arm/aarch32.o
|
||||
|
||||
obj-y += $(KVM)/arm/vgic/vgic.o
|
||||
obj-y += $(KVM)/arm/vgic/vgic-init.o
|
||||
obj-y += $(KVM)/arm/vgic/vgic-irqfd.o
|
||||
obj-y += $(KVM)/arm/vgic/vgic-v2.o
|
||||
obj-y += $(KVM)/arm/vgic/vgic-v3.o
|
||||
obj-y += $(KVM)/arm/vgic/vgic-v4.o
|
||||
obj-y += $(KVM)/arm/vgic/vgic-mmio.o
|
||||
obj-y += $(KVM)/arm/vgic/vgic-mmio-v2.o
|
||||
obj-y += $(KVM)/arm/vgic/vgic-mmio-v3.o
|
||||
obj-y += $(KVM)/arm/vgic/vgic-kvm-device.o
|
||||
obj-y += $(KVM)/arm/vgic/vgic-its.o
|
||||
obj-y += $(KVM)/arm/vgic/vgic-debug.o
|
||||
obj-y += $(KVM)/irqchip.o
|
||||
obj-y += $(KVM)/arm/arch_timer.o
|
File diff suppressed because it is too large
Load Diff
@ -1,130 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2012 - Virtual Open Systems and Columbia University
|
||||
* Authors: Christoffer Dall <c.dall@virtualopensystems.com>
|
||||
*/
|
||||
|
||||
#ifndef __ARM_KVM_COPROC_LOCAL_H__
|
||||
#define __ARM_KVM_COPROC_LOCAL_H__
|
||||
|
||||
struct coproc_params {
|
||||
unsigned long CRn;
|
||||
unsigned long CRm;
|
||||
unsigned long Op1;
|
||||
unsigned long Op2;
|
||||
unsigned long Rt1;
|
||||
unsigned long Rt2;
|
||||
bool is_64bit;
|
||||
bool is_write;
|
||||
};
|
||||
|
||||
struct coproc_reg {
|
||||
/* MRC/MCR/MRRC/MCRR instruction which accesses it. */
|
||||
unsigned long CRn;
|
||||
unsigned long CRm;
|
||||
unsigned long Op1;
|
||||
unsigned long Op2;
|
||||
|
||||
bool is_64bit;
|
||||
|
||||
/* Trapped access from guest, if non-NULL. */
|
||||
bool (*access)(struct kvm_vcpu *,
|
||||
const struct coproc_params *,
|
||||
const struct coproc_reg *);
|
||||
|
||||
/* Initialization for vcpu. */
|
||||
void (*reset)(struct kvm_vcpu *, const struct coproc_reg *);
|
||||
|
||||
/* Index into vcpu_cp15(vcpu, ...), or 0 if we don't need to save it. */
|
||||
unsigned long reg;
|
||||
|
||||
/* Value (usually reset value) */
|
||||
u64 val;
|
||||
};
|
||||
|
||||
static inline void print_cp_instr(const struct coproc_params *p)
|
||||
{
|
||||
/* Look, we even formatted it for you to paste into the table! */
|
||||
if (p->is_64bit) {
|
||||
kvm_pr_unimpl(" { CRm64(%2lu), Op1(%2lu), is64, func_%s },\n",
|
||||
p->CRn, p->Op1, p->is_write ? "write" : "read");
|
||||
} else {
|
||||
kvm_pr_unimpl(" { CRn(%2lu), CRm(%2lu), Op1(%2lu), Op2(%2lu), is32,"
|
||||
" func_%s },\n",
|
||||
p->CRn, p->CRm, p->Op1, p->Op2,
|
||||
p->is_write ? "write" : "read");
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool ignore_write(struct kvm_vcpu *vcpu,
|
||||
const struct coproc_params *p)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool read_zero(struct kvm_vcpu *vcpu,
|
||||
const struct coproc_params *p)
|
||||
{
|
||||
*vcpu_reg(vcpu, p->Rt1) = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Reset functions */
|
||||
static inline void reset_unknown(struct kvm_vcpu *vcpu,
|
||||
const struct coproc_reg *r)
|
||||
{
|
||||
BUG_ON(!r->reg);
|
||||
BUG_ON(r->reg >= ARRAY_SIZE(vcpu->arch.ctxt.cp15));
|
||||
vcpu_cp15(vcpu, r->reg) = 0xdecafbad;
|
||||
}
|
||||
|
||||
static inline void reset_val(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
|
||||
{
|
||||
BUG_ON(!r->reg);
|
||||
BUG_ON(r->reg >= ARRAY_SIZE(vcpu->arch.ctxt.cp15));
|
||||
vcpu_cp15(vcpu, r->reg) = r->val;
|
||||
}
|
||||
|
||||
static inline void reset_unknown64(struct kvm_vcpu *vcpu,
|
||||
const struct coproc_reg *r)
|
||||
{
|
||||
BUG_ON(!r->reg);
|
||||
BUG_ON(r->reg + 1 >= ARRAY_SIZE(vcpu->arch.ctxt.cp15));
|
||||
|
||||
vcpu_cp15(vcpu, r->reg) = 0xdecafbad;
|
||||
vcpu_cp15(vcpu, r->reg+1) = 0xd0c0ffee;
|
||||
}
|
||||
|
||||
static inline int cmp_reg(const struct coproc_reg *i1,
|
||||
const struct coproc_reg *i2)
|
||||
{
|
||||
BUG_ON(i1 == i2);
|
||||
if (!i1)
|
||||
return 1;
|
||||
else if (!i2)
|
||||
return -1;
|
||||
if (i1->CRn != i2->CRn)
|
||||
return i1->CRn - i2->CRn;
|
||||
if (i1->CRm != i2->CRm)
|
||||
return i1->CRm - i2->CRm;
|
||||
if (i1->Op1 != i2->Op1)
|
||||
return i1->Op1 - i2->Op1;
|
||||
if (i1->Op2 != i2->Op2)
|
||||
return i1->Op2 - i2->Op2;
|
||||
return i2->is_64bit - i1->is_64bit;
|
||||
}
|
||||
|
||||
|
||||
#define CRn(_x) .CRn = _x
|
||||
#define CRm(_x) .CRm = _x
|
||||
#define CRm64(_x) .CRn = _x, .CRm = 0
|
||||
#define Op1(_x) .Op1 = _x
|
||||
#define Op2(_x) .Op2 = _x
|
||||
#define is64 .is_64bit = true
|
||||
#define is32 .is_64bit = false
|
||||
|
||||
bool access_vm_reg(struct kvm_vcpu *vcpu,
|
||||
const struct coproc_params *p,
|
||||
const struct coproc_reg *r);
|
||||
|
||||
#endif /* __ARM_KVM_COPROC_LOCAL_H__ */
|
@ -1,39 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2012 - Virtual Open Systems and Columbia University
|
||||
* Authors: Rusty Russell <rusty@rustcorp.au>
|
||||
* Christoffer Dall <c.dall@virtualopensystems.com>
|
||||
*/
|
||||
#include <linux/kvm_host.h>
|
||||
#include <asm/kvm_coproc.h>
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include "coproc.h"
|
||||
|
||||
/*
|
||||
* A15-specific CP15 registers.
|
||||
* CRn denotes the primary register number, but is copied to the CRm in the
|
||||
* user space API for 64-bit register access in line with the terminology used
|
||||
* in the ARM ARM.
|
||||
* Important: Must be sorted ascending by CRn, CRM, Op1, Op2 and with 64-bit
|
||||
* registers preceding 32-bit ones.
|
||||
*/
|
||||
static const struct coproc_reg a15_regs[] = {
|
||||
/* SCTLR: swapped by interrupt.S. */
|
||||
{ CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32,
|
||||
access_vm_reg, reset_val, c1_SCTLR, 0x00C50078 },
|
||||
};
|
||||
|
||||
static struct kvm_coproc_target_table a15_target_table = {
|
||||
.target = KVM_ARM_TARGET_CORTEX_A15,
|
||||
.table = a15_regs,
|
||||
.num = ARRAY_SIZE(a15_regs),
|
||||
};
|
||||
|
||||
static int __init coproc_a15_init(void)
|
||||
{
|
||||
kvm_register_target_coproc_table(&a15_target_table);
|
||||
return 0;
|
||||
}
|
||||
late_initcall(coproc_a15_init);
|
@ -1,42 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2012 - Virtual Open Systems and Columbia University
|
||||
* Copyright (C) 2013 - ARM Ltd
|
||||
*
|
||||
* Authors: Rusty Russell <rusty@rustcorp.au>
|
||||
* Christoffer Dall <c.dall@virtualopensystems.com>
|
||||
* Jonathan Austin <jonathan.austin@arm.com>
|
||||
*/
|
||||
#include <linux/kvm_host.h>
|
||||
#include <asm/kvm_coproc.h>
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include "coproc.h"
|
||||
|
||||
/*
|
||||
* Cortex-A7 specific CP15 registers.
|
||||
* CRn denotes the primary register number, but is copied to the CRm in the
|
||||
* user space API for 64-bit register access in line with the terminology used
|
||||
* in the ARM ARM.
|
||||
* Important: Must be sorted ascending by CRn, CRM, Op1, Op2 and with 64-bit
|
||||
* registers preceding 32-bit ones.
|
||||
*/
|
||||
static const struct coproc_reg a7_regs[] = {
|
||||
/* SCTLR: swapped by interrupt.S. */
|
||||
{ CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32,
|
||||
access_vm_reg, reset_val, c1_SCTLR, 0x00C50878 },
|
||||
};
|
||||
|
||||
static struct kvm_coproc_target_table a7_target_table = {
|
||||
.target = KVM_ARM_TARGET_CORTEX_A7,
|
||||
.table = a7_regs,
|
||||
.num = ARRAY_SIZE(a7_regs),
|
||||
};
|
||||
|
||||
static int __init coproc_a7_init(void)
|
||||
{
|
||||
kvm_register_target_coproc_table(&a7_target_table);
|
||||
return 0;
|
||||
}
|
||||
late_initcall(coproc_a7_init);
|
@ -1,166 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2012 - Virtual Open Systems and Columbia University
|
||||
* Author: Christoffer Dall <c.dall@virtualopensystems.com>
|
||||
*/
|
||||
|
||||
#include <linux/mm.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <asm/kvm_arm.h>
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <asm/opcodes.h>
|
||||
#include <trace/events/kvm.h>
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
#define VCPU_NR_MODES 6
|
||||
#define VCPU_REG_OFFSET_USR 0
|
||||
#define VCPU_REG_OFFSET_FIQ 1
|
||||
#define VCPU_REG_OFFSET_IRQ 2
|
||||
#define VCPU_REG_OFFSET_SVC 3
|
||||
#define VCPU_REG_OFFSET_ABT 4
|
||||
#define VCPU_REG_OFFSET_UND 5
|
||||
#define REG_OFFSET(_reg) \
|
||||
(offsetof(struct kvm_regs, _reg) / sizeof(u32))
|
||||
|
||||
#define USR_REG_OFFSET(_num) REG_OFFSET(usr_regs.uregs[_num])
|
||||
|
||||
static const unsigned long vcpu_reg_offsets[VCPU_NR_MODES][15] = {
|
||||
/* USR/SYS Registers */
|
||||
[VCPU_REG_OFFSET_USR] = {
|
||||
USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
|
||||
USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
|
||||
USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
|
||||
USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
|
||||
USR_REG_OFFSET(12), USR_REG_OFFSET(13), USR_REG_OFFSET(14),
|
||||
},
|
||||
|
||||
/* FIQ Registers */
|
||||
[VCPU_REG_OFFSET_FIQ] = {
|
||||
USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
|
||||
USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
|
||||
USR_REG_OFFSET(6), USR_REG_OFFSET(7),
|
||||
REG_OFFSET(fiq_regs[0]), /* r8 */
|
||||
REG_OFFSET(fiq_regs[1]), /* r9 */
|
||||
REG_OFFSET(fiq_regs[2]), /* r10 */
|
||||
REG_OFFSET(fiq_regs[3]), /* r11 */
|
||||
REG_OFFSET(fiq_regs[4]), /* r12 */
|
||||
REG_OFFSET(fiq_regs[5]), /* r13 */
|
||||
REG_OFFSET(fiq_regs[6]), /* r14 */
|
||||
},
|
||||
|
||||
/* IRQ Registers */
|
||||
[VCPU_REG_OFFSET_IRQ] = {
|
||||
USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
|
||||
USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
|
||||
USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
|
||||
USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
|
||||
USR_REG_OFFSET(12),
|
||||
REG_OFFSET(irq_regs[0]), /* r13 */
|
||||
REG_OFFSET(irq_regs[1]), /* r14 */
|
||||
},
|
||||
|
||||
/* SVC Registers */
|
||||
[VCPU_REG_OFFSET_SVC] = {
|
||||
USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
|
||||
USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
|
||||
USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
|
||||
USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
|
||||
USR_REG_OFFSET(12),
|
||||
REG_OFFSET(svc_regs[0]), /* r13 */
|
||||
REG_OFFSET(svc_regs[1]), /* r14 */
|
||||
},
|
||||
|
||||
/* ABT Registers */
|
||||
[VCPU_REG_OFFSET_ABT] = {
|
||||
USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
|
||||
USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
|
||||
USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
|
||||
USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
|
||||
USR_REG_OFFSET(12),
|
||||
REG_OFFSET(abt_regs[0]), /* r13 */
|
||||
REG_OFFSET(abt_regs[1]), /* r14 */
|
||||
},
|
||||
|
||||
/* UND Registers */
|
||||
[VCPU_REG_OFFSET_UND] = {
|
||||
USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
|
||||
USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
|
||||
USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
|
||||
USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
|
||||
USR_REG_OFFSET(12),
|
||||
REG_OFFSET(und_regs[0]), /* r13 */
|
||||
REG_OFFSET(und_regs[1]), /* r14 */
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Return a pointer to the register number valid in the current mode of
|
||||
* the virtual CPU.
|
||||
*/
|
||||
unsigned long *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num)
|
||||
{
|
||||
unsigned long *reg_array = (unsigned long *)&vcpu->arch.ctxt.gp_regs;
|
||||
unsigned long mode = *vcpu_cpsr(vcpu) & MODE_MASK;
|
||||
|
||||
switch (mode) {
|
||||
case USR_MODE...SVC_MODE:
|
||||
mode &= ~MODE32_BIT; /* 0 ... 3 */
|
||||
break;
|
||||
|
||||
case ABT_MODE:
|
||||
mode = VCPU_REG_OFFSET_ABT;
|
||||
break;
|
||||
|
||||
case UND_MODE:
|
||||
mode = VCPU_REG_OFFSET_UND;
|
||||
break;
|
||||
|
||||
case SYSTEM_MODE:
|
||||
mode = VCPU_REG_OFFSET_USR;
|
||||
break;
|
||||
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
return reg_array + vcpu_reg_offsets[mode][reg_num];
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the SPSR for the current mode of the virtual CPU.
|
||||
*/
|
||||
unsigned long *__vcpu_spsr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long mode = *vcpu_cpsr(vcpu) & MODE_MASK;
|
||||
switch (mode) {
|
||||
case SVC_MODE:
|
||||
return &vcpu->arch.ctxt.gp_regs.KVM_ARM_SVC_spsr;
|
||||
case ABT_MODE:
|
||||
return &vcpu->arch.ctxt.gp_regs.KVM_ARM_ABT_spsr;
|
||||
case UND_MODE:
|
||||
return &vcpu->arch.ctxt.gp_regs.KVM_ARM_UND_spsr;
|
||||
case IRQ_MODE:
|
||||
return &vcpu->arch.ctxt.gp_regs.KVM_ARM_IRQ_spsr;
|
||||
case FIQ_MODE:
|
||||
return &vcpu->arch.ctxt.gp_regs.KVM_ARM_FIQ_spsr;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Inject exceptions into the guest
|
||||
*/
|
||||
|
||||
/**
|
||||
* kvm_inject_vabt - inject an async abort / SError into the guest
|
||||
* @vcpu: The VCPU to receive the exception
|
||||
*
|
||||
* It is assumed that this code is called from the VCPU thread and that the
|
||||
* VCPU therefore is not currently executing guest code.
|
||||
*/
|
||||
void kvm_inject_vabt(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
*vcpu_hcr(vcpu) |= HCR_VA;
|
||||
}
|
@ -1,387 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2012 - Virtual Open Systems and Columbia University
|
||||
* Author: Christoffer Dall <c.dall@virtualopensystems.com>
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/fs.h>
|
||||
#include <kvm/arm_psci.h>
|
||||
#include <asm/cputype.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/kvm.h>
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <asm/kvm_coproc.h>
|
||||
|
||||
#define VM_STAT(x) { #x, offsetof(struct kvm, stat.x), KVM_STAT_VM }
|
||||
#define VCPU_STAT(x) { #x, offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU }
|
||||
|
||||
struct kvm_stats_debugfs_item debugfs_entries[] = {
|
||||
VCPU_STAT(halt_successful_poll),
|
||||
VCPU_STAT(halt_attempted_poll),
|
||||
VCPU_STAT(halt_poll_invalid),
|
||||
VCPU_STAT(halt_wakeup),
|
||||
VCPU_STAT(hvc_exit_stat),
|
||||
VCPU_STAT(wfe_exit_stat),
|
||||
VCPU_STAT(wfi_exit_stat),
|
||||
VCPU_STAT(mmio_exit_user),
|
||||
VCPU_STAT(mmio_exit_kernel),
|
||||
VCPU_STAT(exits),
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static u64 core_reg_offset_from_id(u64 id)
|
||||
{
|
||||
return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
|
||||
}
|
||||
|
||||
static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
||||
{
|
||||
u32 __user *uaddr = (u32 __user *)(long)reg->addr;
|
||||
struct kvm_regs *regs = &vcpu->arch.ctxt.gp_regs;
|
||||
u64 off;
|
||||
|
||||
if (KVM_REG_SIZE(reg->id) != 4)
|
||||
return -ENOENT;
|
||||
|
||||
/* Our ID is an index into the kvm_regs struct. */
|
||||
off = core_reg_offset_from_id(reg->id);
|
||||
if (off >= sizeof(*regs) / KVM_REG_SIZE(reg->id))
|
||||
return -ENOENT;
|
||||
|
||||
return put_user(((u32 *)regs)[off], uaddr);
|
||||
}
|
||||
|
||||
static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
||||
{
|
||||
u32 __user *uaddr = (u32 __user *)(long)reg->addr;
|
||||
struct kvm_regs *regs = &vcpu->arch.ctxt.gp_regs;
|
||||
u64 off, val;
|
||||
|
||||
if (KVM_REG_SIZE(reg->id) != 4)
|
||||
return -ENOENT;
|
||||
|
||||
/* Our ID is an index into the kvm_regs struct. */
|
||||
off = core_reg_offset_from_id(reg->id);
|
||||
if (off >= sizeof(*regs) / KVM_REG_SIZE(reg->id))
|
||||
return -ENOENT;
|
||||
|
||||
if (get_user(val, uaddr) != 0)
|
||||
return -EFAULT;
|
||||
|
||||
if (off == KVM_REG_ARM_CORE_REG(usr_regs.ARM_cpsr)) {
|
||||
unsigned long mode = val & MODE_MASK;
|
||||
switch (mode) {
|
||||
case USR_MODE:
|
||||
case FIQ_MODE:
|
||||
case IRQ_MODE:
|
||||
case SVC_MODE:
|
||||
case ABT_MODE:
|
||||
case UND_MODE:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
((u32 *)regs)[off] = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#define NUM_TIMER_REGS 3
|
||||
|
||||
static bool is_timer_reg(u64 index)
|
||||
{
|
||||
switch (index) {
|
||||
case KVM_REG_ARM_TIMER_CTL:
|
||||
case KVM_REG_ARM_TIMER_CNT:
|
||||
case KVM_REG_ARM_TIMER_CVAL:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
|
||||
{
|
||||
if (put_user(KVM_REG_ARM_TIMER_CTL, uindices))
|
||||
return -EFAULT;
|
||||
uindices++;
|
||||
if (put_user(KVM_REG_ARM_TIMER_CNT, uindices))
|
||||
return -EFAULT;
|
||||
uindices++;
|
||||
if (put_user(KVM_REG_ARM_TIMER_CVAL, uindices))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
||||
{
|
||||
void __user *uaddr = (void __user *)(long)reg->addr;
|
||||
u64 val;
|
||||
int ret;
|
||||
|
||||
ret = copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id));
|
||||
if (ret != 0)
|
||||
return -EFAULT;
|
||||
|
||||
return kvm_arm_timer_set_reg(vcpu, reg->id, val);
|
||||
}
|
||||
|
||||
static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
||||
{
|
||||
void __user *uaddr = (void __user *)(long)reg->addr;
|
||||
u64 val;
|
||||
|
||||
val = kvm_arm_timer_get_reg(vcpu, reg->id);
|
||||
return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
static unsigned long num_core_regs(void)
|
||||
{
|
||||
return sizeof(struct kvm_regs) / sizeof(u32);
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_arm_num_regs - how many registers do we present via KVM_GET_ONE_REG
|
||||
*
|
||||
* This is for all registers.
|
||||
*/
|
||||
unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return num_core_regs() + kvm_arm_num_coproc_regs(vcpu)
|
||||
+ kvm_arm_get_fw_num_regs(vcpu)
|
||||
+ NUM_TIMER_REGS;
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_arm_copy_reg_indices - get indices of all registers.
|
||||
*
|
||||
* We do core registers right here, then we append coproc regs.
|
||||
*/
|
||||
int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
|
||||
{
|
||||
unsigned int i;
|
||||
const u64 core_reg = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_CORE;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < sizeof(struct kvm_regs)/sizeof(u32); i++) {
|
||||
if (put_user(core_reg | i, uindices))
|
||||
return -EFAULT;
|
||||
uindices++;
|
||||
}
|
||||
|
||||
ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
|
||||
if (ret)
|
||||
return ret;
|
||||
uindices += kvm_arm_get_fw_num_regs(vcpu);
|
||||
|
||||
ret = copy_timer_indices(vcpu, uindices);
|
||||
if (ret)
|
||||
return ret;
|
||||
uindices += NUM_TIMER_REGS;
|
||||
|
||||
return kvm_arm_copy_coproc_indices(vcpu, uindices);
|
||||
}
|
||||
|
||||
int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
||||
{
|
||||
/* We currently use nothing arch-specific in upper 32 bits */
|
||||
if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM >> 32)
|
||||
return -EINVAL;
|
||||
|
||||
/* Register group 16 means we want a core register. */
|
||||
if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
|
||||
return get_core_reg(vcpu, reg);
|
||||
|
||||
if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
|
||||
return kvm_arm_get_fw_reg(vcpu, reg);
|
||||
|
||||
if (is_timer_reg(reg->id))
|
||||
return get_timer_reg(vcpu, reg);
|
||||
|
||||
return kvm_arm_coproc_get_reg(vcpu, reg);
|
||||
}
|
||||
|
||||
int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
||||
{
|
||||
/* We currently use nothing arch-specific in upper 32 bits */
|
||||
if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM >> 32)
|
||||
return -EINVAL;
|
||||
|
||||
/* Register group 16 means we set a core register. */
|
||||
if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
|
||||
return set_core_reg(vcpu, reg);
|
||||
|
||||
if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
|
||||
return kvm_arm_set_fw_reg(vcpu, reg);
|
||||
|
||||
if (is_timer_reg(reg->id))
|
||||
return set_timer_reg(vcpu, reg);
|
||||
|
||||
return kvm_arm_coproc_set_reg(vcpu, reg);
|
||||
}
|
||||
|
||||
int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
|
||||
struct kvm_sregs *sregs)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
|
||||
struct kvm_sregs *sregs)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
int __kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
|
||||
struct kvm_vcpu_events *events)
|
||||
{
|
||||
events->exception.serror_pending = !!(*vcpu_hcr(vcpu) & HCR_VA);
|
||||
|
||||
/*
|
||||
* We never return a pending ext_dabt here because we deliver it to
|
||||
* the virtual CPU directly when setting the event and it's no longer
|
||||
* 'pending' at this point.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
|
||||
struct kvm_vcpu_events *events)
|
||||
{
|
||||
bool serror_pending = events->exception.serror_pending;
|
||||
bool has_esr = events->exception.serror_has_esr;
|
||||
bool ext_dabt_pending = events->exception.ext_dabt_pending;
|
||||
|
||||
if (serror_pending && has_esr)
|
||||
return -EINVAL;
|
||||
else if (serror_pending)
|
||||
kvm_inject_vabt(vcpu);
|
||||
|
||||
if (ext_dabt_pending)
|
||||
kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __attribute_const__ kvm_target_cpu(void)
|
||||
{
|
||||
switch (read_cpuid_part()) {
|
||||
case ARM_CPU_PART_CORTEX_A7:
|
||||
return KVM_ARM_TARGET_CORTEX_A7;
|
||||
case ARM_CPU_PART_CORTEX_A15:
|
||||
return KVM_ARM_TARGET_CORTEX_A15;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int kvm_vcpu_preferred_target(struct kvm_vcpu_init *init)
|
||||
{
|
||||
int target = kvm_target_cpu();
|
||||
|
||||
if (target < 0)
|
||||
return -ENODEV;
|
||||
|
||||
memset(init, 0, sizeof(*init));
|
||||
|
||||
/*
|
||||
* For now, we don't return any features.
|
||||
* In future, we might use features to return target
|
||||
* specific features available for the preferred
|
||||
* target type.
|
||||
*/
|
||||
init->target = (__u32)target;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
|
||||
struct kvm_translation *tr)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
|
||||
struct kvm_guest_debug *dbg)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu,
|
||||
struct kvm_device_attr *attr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (attr->group) {
|
||||
case KVM_ARM_VCPU_TIMER_CTRL:
|
||||
ret = kvm_arm_timer_set_attr(vcpu, attr);
|
||||
break;
|
||||
default:
|
||||
ret = -ENXIO;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu,
|
||||
struct kvm_device_attr *attr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (attr->group) {
|
||||
case KVM_ARM_VCPU_TIMER_CTRL:
|
||||
ret = kvm_arm_timer_get_attr(vcpu, attr);
|
||||
break;
|
||||
default:
|
||||
ret = -ENXIO;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu,
|
||||
struct kvm_device_attr *attr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (attr->group) {
|
||||
case KVM_ARM_VCPU_TIMER_CTRL:
|
||||
ret = kvm_arm_timer_has_attr(vcpu, attr);
|
||||
break;
|
||||
default:
|
||||
ret = -ENXIO;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
@ -1,175 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2012 - Virtual Open Systems and Columbia University
|
||||
* Author: Christoffer Dall <c.dall@virtualopensystems.com>
|
||||
*/
|
||||
|
||||
#include <linux/kvm.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <asm/kvm_coproc.h>
|
||||
#include <asm/kvm_mmu.h>
|
||||
#include <kvm/arm_hypercalls.h>
|
||||
#include <trace/events/kvm.h>
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
typedef int (*exit_handle_fn)(struct kvm_vcpu *, struct kvm_run *);
|
||||
|
||||
static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
{
|
||||
int ret;
|
||||
|
||||
trace_kvm_hvc(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0),
|
||||
kvm_vcpu_hvc_get_imm(vcpu));
|
||||
vcpu->stat.hvc_exit_stat++;
|
||||
|
||||
ret = kvm_hvc_call_handler(vcpu);
|
||||
if (ret < 0) {
|
||||
vcpu_set_reg(vcpu, 0, ~0UL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
{
|
||||
/*
|
||||
* "If an SMC instruction executed at Non-secure EL1 is
|
||||
* trapped to EL2 because HCR_EL2.TSC is 1, the exception is a
|
||||
* Trap exception, not a Secure Monitor Call exception [...]"
|
||||
*
|
||||
* We need to advance the PC after the trap, as it would
|
||||
* otherwise return to the same address...
|
||||
*/
|
||||
vcpu_set_reg(vcpu, 0, ~0UL);
|
||||
kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_handle_wfx - handle a WFI or WFE instructions trapped in guests
|
||||
* @vcpu: the vcpu pointer
|
||||
* @run: the kvm_run structure pointer
|
||||
*
|
||||
* WFE: Yield the CPU and come back to this vcpu when the scheduler
|
||||
* decides to.
|
||||
* WFI: Simply call kvm_vcpu_block(), which will halt execution of
|
||||
* world-switches and schedule other host processes until there is an
|
||||
* incoming IRQ or FIQ to the VM.
|
||||
*/
|
||||
static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
{
|
||||
if (kvm_vcpu_get_hsr(vcpu) & HSR_WFI_IS_WFE) {
|
||||
trace_kvm_wfx(*vcpu_pc(vcpu), true);
|
||||
vcpu->stat.wfe_exit_stat++;
|
||||
kvm_vcpu_on_spin(vcpu, vcpu_mode_priv(vcpu));
|
||||
} else {
|
||||
trace_kvm_wfx(*vcpu_pc(vcpu), false);
|
||||
vcpu->stat.wfi_exit_stat++;
|
||||
kvm_vcpu_block(vcpu);
|
||||
kvm_clear_request(KVM_REQ_UNHALT, vcpu);
|
||||
}
|
||||
|
||||
kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
{
|
||||
u32 hsr = kvm_vcpu_get_hsr(vcpu);
|
||||
|
||||
kvm_pr_unimpl("Unknown exception class: hsr: %#08x\n",
|
||||
hsr);
|
||||
|
||||
kvm_inject_undefined(vcpu);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static exit_handle_fn arm_exit_handlers[] = {
|
||||
[0 ... HSR_EC_MAX] = kvm_handle_unknown_ec,
|
||||
[HSR_EC_WFI] = kvm_handle_wfx,
|
||||
[HSR_EC_CP15_32] = kvm_handle_cp15_32,
|
||||
[HSR_EC_CP15_64] = kvm_handle_cp15_64,
|
||||
[HSR_EC_CP14_MR] = kvm_handle_cp14_32,
|
||||
[HSR_EC_CP14_LS] = kvm_handle_cp14_load_store,
|
||||
[HSR_EC_CP14_64] = kvm_handle_cp14_64,
|
||||
[HSR_EC_CP_0_13] = kvm_handle_cp_0_13_access,
|
||||
[HSR_EC_CP10_ID] = kvm_handle_cp10_id,
|
||||
[HSR_EC_HVC] = handle_hvc,
|
||||
[HSR_EC_SMC] = handle_smc,
|
||||
[HSR_EC_IABT] = kvm_handle_guest_abort,
|
||||
[HSR_EC_DABT] = kvm_handle_guest_abort,
|
||||
};
|
||||
|
||||
static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u8 hsr_ec = kvm_vcpu_trap_get_class(vcpu);
|
||||
|
||||
return arm_exit_handlers[hsr_ec];
|
||||
}
|
||||
|
||||
/*
|
||||
* Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on
|
||||
* proper exit to userspace.
|
||||
*/
|
||||
int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
||||
int exception_index)
|
||||
{
|
||||
exit_handle_fn exit_handler;
|
||||
|
||||
if (ARM_ABORT_PENDING(exception_index)) {
|
||||
u8 hsr_ec = kvm_vcpu_trap_get_class(vcpu);
|
||||
|
||||
/*
|
||||
* HVC/SMC already have an adjusted PC, which we need
|
||||
* to correct in order to return to after having
|
||||
* injected the abort.
|
||||
*/
|
||||
if (hsr_ec == HSR_EC_HVC || hsr_ec == HSR_EC_SMC) {
|
||||
u32 adj = kvm_vcpu_trap_il_is32bit(vcpu) ? 4 : 2;
|
||||
*vcpu_pc(vcpu) -= adj;
|
||||
}
|
||||
|
||||
kvm_inject_vabt(vcpu);
|
||||
return 1;
|
||||
}
|
||||
|
||||
exception_index = ARM_EXCEPTION_CODE(exception_index);
|
||||
|
||||
switch (exception_index) {
|
||||
case ARM_EXCEPTION_IRQ:
|
||||
return 1;
|
||||
case ARM_EXCEPTION_HVC:
|
||||
/*
|
||||
* See ARM ARM B1.14.1: "Hyp traps on instructions
|
||||
* that fail their condition code check"
|
||||
*/
|
||||
if (!kvm_condition_valid(vcpu)) {
|
||||
kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
|
||||
return 1;
|
||||
}
|
||||
|
||||
exit_handler = kvm_get_exit_handler(vcpu);
|
||||
|
||||
return exit_handler(vcpu, run);
|
||||
case ARM_EXCEPTION_DATA_ABORT:
|
||||
kvm_inject_vabt(vcpu);
|
||||
return 1;
|
||||
case ARM_EXCEPTION_HYP_GONE:
|
||||
/*
|
||||
* HYP has been reset to the hyp-stub. This happens
|
||||
* when a guest is pre-empted by kvm_reboot()'s
|
||||
* shutdown call.
|
||||
*/
|
||||
run->exit_reason = KVM_EXIT_FAIL_ENTRY;
|
||||
return 0;
|
||||
default:
|
||||
kvm_pr_unimpl("Unsupported exception type: %d",
|
||||
exception_index);
|
||||
run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for Kernel-based Virtual Machine module, HYP part
|
||||
#
|
||||
|
||||
ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING
|
||||
|
||||
KVM=../../../../virt/kvm
|
||||
|
||||
CFLAGS_ARMV7VE :=$(call cc-option, -march=armv7ve)
|
||||
|
||||
obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v3-sr.o
|
||||
obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/timer-sr.o
|
||||
obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/aarch32.o
|
||||
|
||||
obj-$(CONFIG_KVM_ARM_HOST) += tlb.o
|
||||
obj-$(CONFIG_KVM_ARM_HOST) += cp15-sr.o
|
||||
obj-$(CONFIG_KVM_ARM_HOST) += vfp.o
|
||||
obj-$(CONFIG_KVM_ARM_HOST) += banked-sr.o
|
||||
CFLAGS_banked-sr.o += $(CFLAGS_ARMV7VE)
|
||||
|
||||
obj-$(CONFIG_KVM_ARM_HOST) += entry.o
|
||||
obj-$(CONFIG_KVM_ARM_HOST) += hyp-entry.o
|
||||
obj-$(CONFIG_KVM_ARM_HOST) += switch.o
|
||||
CFLAGS_switch.o += $(CFLAGS_ARMV7VE)
|
||||
obj-$(CONFIG_KVM_ARM_HOST) += s2-setup.o
|
||||
|
||||
# KVM code is run at a different exception code with a different map, so
|
||||
# compiler instrumentation that inserts callbacks or checks into the code may
|
||||
# cause crashes. Just disable it.
|
||||
GCOV_PROFILE := n
|
||||
KASAN_SANITIZE := n
|
||||
UBSAN_SANITIZE := n
|
||||
KCOV_INSTRUMENT := n
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user