mirror of
https://github.com/torvalds/linux.git
synced 2026-06-08 14:42:37 +02:00
LSK Android 14.11 v3.10
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJUdvtFAAoJECTWi3JdVIfQn3sH/i7lx5lXGQcZ6HsynmZkqA4J 9G0kenDhW6Rm0YGetIR3DMTNSkrYbL3rBLPd6Vl+CXx8l1hORlostEBvtMnFK0u/ B289o6qtW7dc8zzYW5jpwMgC+WNeFD4Gn7/x3bDguYLqMPtbbrr3vzsGaKKmScbJ AOyOsZR4TVUi+SUzeCbN8YDW9HSQNhVYrA/qcI6ImASOaKYN4i0stHKMUVoI4HxF +e9F40P7Lg8zBM4Ss8X9yYlFxX2EwuKLNrelCvXPo6BBcvjZZM4C4MUvh9c8AyDa 0LiCgVL3fXb4S+bmJwgRKYm5C9TPpulL3VUDn3fGuVqy9HHfBaC62kc8XX8ciAo= =aswn -----END PGP SIGNATURE----- Merge tag 'lsk-v3.10-android-14.11' LSK Android 14.11 v3.10 Conflicts: arch/arm/include/asm/cputype.h
This commit is contained in:
commit
d03390bfcd
|
|
@ -102,3 +102,10 @@ Translation table lookup with 64KB pages:
|
|||
| | +--------------------------> [41:29] L2 index (only 38:29 used)
|
||||
| +-------------------------------> [47:42] L1 index (not used)
|
||||
+-------------------------------------------------> [63] TTBR0/1
|
||||
|
||||
When using KVM, the hypervisor maps kernel pages in EL2, at a fixed
|
||||
offset from the kernel VA (top 24bits of the kernel VA set to zero):
|
||||
|
||||
Start End Size Use
|
||||
-----------------------------------------------------------------------
|
||||
0000004000000000 0000007fffffffff 256GB kernel objects mapped in HYP
|
||||
|
|
|
|||
|
|
@ -49,6 +49,11 @@ Optional
|
|||
regions, used when the GIC doesn't have banked registers. The offset is
|
||||
cpu-offset * cpu-nr.
|
||||
|
||||
- arm,routable-irqs : Total number of gic irq inputs which are not directly
|
||||
connected from the peripherals, but are routed dynamically
|
||||
by a crossbar/multiplexer preceding the GIC. The GIC irq
|
||||
input line is assigned dynamically when the corresponding
|
||||
peripheral's crossbar line is mapped.
|
||||
Example:
|
||||
|
||||
intc: interrupt-controller@fff11000 {
|
||||
|
|
@ -56,6 +61,7 @@ Example:
|
|||
#interrupt-cells = <3>;
|
||||
#address-cells = <1>;
|
||||
interrupt-controller;
|
||||
arm,routable-irqs = <160>;
|
||||
reg = <0xfff11000 0x1000>,
|
||||
<0xfff10100 0x100>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,15 +19,20 @@ Example:
|
|||
* Mailbox Client
|
||||
|
||||
Required property:
|
||||
- mbox: List of phandle and mailbox channel specifier.
|
||||
- mboxes: List of phandle and mailbox channel specifiers.
|
||||
|
||||
Optional property:
|
||||
- mbox-names: List of identifier strings for each mailbox channel
|
||||
required by the client.
|
||||
required by the client. The use of this property
|
||||
is discouraged in favor of using index in list of
|
||||
'mboxes' while requesting a mailbox. Instead the
|
||||
platforms may define channel indices, in DT headers,
|
||||
to something legible.
|
||||
|
||||
Example:
|
||||
pwr_cntrl: power {
|
||||
...
|
||||
mbox-names = "pwr-ctrl", "rpc";
|
||||
mbox = <&mailbox 0
|
||||
mboxes = <&mailbox 0
|
||||
&mailbox 1>;
|
||||
};
|
||||
|
|
|
|||
164
Documentation/lzo.txt
Normal file
164
Documentation/lzo.txt
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
|
||||
LZO stream format as understood by Linux's LZO decompressor
|
||||
===========================================================
|
||||
|
||||
Introduction
|
||||
|
||||
This is not a specification. No specification seems to be publicly available
|
||||
for the LZO stream format. This document describes what input format the LZO
|
||||
decompressor as implemented in the Linux kernel understands. The file subject
|
||||
of this analysis is lib/lzo/lzo1x_decompress_safe.c. No analysis was made on
|
||||
the compressor nor on any other implementations though it seems likely that
|
||||
the format matches the standard one. The purpose of this document is to
|
||||
better understand what the code does in order to propose more efficient fixes
|
||||
for future bug reports.
|
||||
|
||||
Description
|
||||
|
||||
The stream is composed of a series of instructions, operands, and data. The
|
||||
instructions consist in a few bits representing an opcode, and bits forming
|
||||
the operands for the instruction, whose size and position depend on the
|
||||
opcode and on the number of literals copied by previous instruction. The
|
||||
operands are used to indicate :
|
||||
|
||||
- a distance when copying data from the dictionary (past output buffer)
|
||||
- a length (number of bytes to copy from dictionary)
|
||||
- the number of literals to copy, which is retained in variable "state"
|
||||
as a piece of information for next instructions.
|
||||
|
||||
Optionally depending on the opcode and operands, extra data may follow. These
|
||||
extra data can be a complement for the operand (eg: a length or a distance
|
||||
encoded on larger values), or a literal to be copied to the output buffer.
|
||||
|
||||
The first byte of the block follows a different encoding from other bytes, it
|
||||
seems to be optimized for literal use only, since there is no dictionary yet
|
||||
prior to that byte.
|
||||
|
||||
Lengths are always encoded on a variable size starting with a small number
|
||||
of bits in the operand. If the number of bits isn't enough to represent the
|
||||
length, up to 255 may be added in increments by consuming more bytes with a
|
||||
rate of at most 255 per extra byte (thus the compression ratio cannot exceed
|
||||
around 255:1). The variable length encoding using #bits is always the same :
|
||||
|
||||
length = byte & ((1 << #bits) - 1)
|
||||
if (!length) {
|
||||
length = ((1 << #bits) - 1)
|
||||
length += 255*(number of zero bytes)
|
||||
length += first-non-zero-byte
|
||||
}
|
||||
length += constant (generally 2 or 3)
|
||||
|
||||
For references to the dictionary, distances are relative to the output
|
||||
pointer. Distances are encoded using very few bits belonging to certain
|
||||
ranges, resulting in multiple copy instructions using different encodings.
|
||||
Certain encodings involve one extra byte, others involve two extra bytes
|
||||
forming a little-endian 16-bit quantity (marked LE16 below).
|
||||
|
||||
After any instruction except the large literal copy, 0, 1, 2 or 3 literals
|
||||
are copied before starting the next instruction. The number of literals that
|
||||
were copied may change the meaning and behaviour of the next instruction. In
|
||||
practice, only one instruction needs to know whether 0, less than 4, or more
|
||||
literals were copied. This is the information stored in the <state> variable
|
||||
in this implementation. This number of immediate literals to be copied is
|
||||
generally encoded in the last two bits of the instruction but may also be
|
||||
taken from the last two bits of an extra operand (eg: distance).
|
||||
|
||||
End of stream is declared when a block copy of distance 0 is seen. Only one
|
||||
instruction may encode this distance (0001HLLL), it takes one LE16 operand
|
||||
for the distance, thus requiring 3 bytes.
|
||||
|
||||
IMPORTANT NOTE : in the code some length checks are missing because certain
|
||||
instructions are called under the assumption that a certain number of bytes
|
||||
follow because it has already been garanteed before parsing the instructions.
|
||||
They just have to "refill" this credit if they consume extra bytes. This is
|
||||
an implementation design choice independant on the algorithm or encoding.
|
||||
|
||||
Byte sequences
|
||||
|
||||
First byte encoding :
|
||||
|
||||
0..17 : follow regular instruction encoding, see below. It is worth
|
||||
noting that codes 16 and 17 will represent a block copy from
|
||||
the dictionary which is empty, and that they will always be
|
||||
invalid at this place.
|
||||
|
||||
18..21 : copy 0..3 literals
|
||||
state = (byte - 17) = 0..3 [ copy <state> literals ]
|
||||
skip byte
|
||||
|
||||
22..255 : copy literal string
|
||||
length = (byte - 17) = 4..238
|
||||
state = 4 [ don't copy extra literals ]
|
||||
skip byte
|
||||
|
||||
Instruction encoding :
|
||||
|
||||
0 0 0 0 X X X X (0..15)
|
||||
Depends on the number of literals copied by the last instruction.
|
||||
If last instruction did not copy any literal (state == 0), this
|
||||
encoding will be a copy of 4 or more literal, and must be interpreted
|
||||
like this :
|
||||
|
||||
0 0 0 0 L L L L (0..15) : copy long literal string
|
||||
length = 3 + (L ?: 15 + (zero_bytes * 255) + non_zero_byte)
|
||||
state = 4 (no extra literals are copied)
|
||||
|
||||
If last instruction used to copy between 1 to 3 literals (encoded in
|
||||
the instruction's opcode or distance), the instruction is a copy of a
|
||||
2-byte block from the dictionary within a 1kB distance. It is worth
|
||||
noting that this instruction provides little savings since it uses 2
|
||||
bytes to encode a copy of 2 other bytes but it encodes the number of
|
||||
following literals for free. It must be interpreted like this :
|
||||
|
||||
0 0 0 0 D D S S (0..15) : copy 2 bytes from <= 1kB distance
|
||||
length = 2
|
||||
state = S (copy S literals after this block)
|
||||
Always followed by exactly one byte : H H H H H H H H
|
||||
distance = (H << 2) + D + 1
|
||||
|
||||
If last instruction used to copy 4 or more literals (as detected by
|
||||
state == 4), the instruction becomes a copy of a 3-byte block from the
|
||||
dictionary from a 2..3kB distance, and must be interpreted like this :
|
||||
|
||||
0 0 0 0 D D S S (0..15) : copy 3 bytes from 2..3 kB distance
|
||||
length = 3
|
||||
state = S (copy S literals after this block)
|
||||
Always followed by exactly one byte : H H H H H H H H
|
||||
distance = (H << 2) + D + 2049
|
||||
|
||||
0 0 0 1 H L L L (16..31)
|
||||
Copy of a block within 16..48kB distance (preferably less than 10B)
|
||||
length = 2 + (L ?: 7 + (zero_bytes * 255) + non_zero_byte)
|
||||
Always followed by exactly one LE16 : D D D D D D D D : D D D D D D S S
|
||||
distance = 16384 + (H << 14) + D
|
||||
state = S (copy S literals after this block)
|
||||
End of stream is reached if distance == 16384
|
||||
|
||||
0 0 1 L L L L L (32..63)
|
||||
Copy of small block within 16kB distance (preferably less than 34B)
|
||||
length = 2 + (L ?: 31 + (zero_bytes * 255) + non_zero_byte)
|
||||
Always followed by exactly one LE16 : D D D D D D D D : D D D D D D S S
|
||||
distance = D + 1
|
||||
state = S (copy S literals after this block)
|
||||
|
||||
0 1 L D D D S S (64..127)
|
||||
Copy 3-4 bytes from block within 2kB distance
|
||||
state = S (copy S literals after this block)
|
||||
length = 3 + L
|
||||
Always followed by exactly one byte : H H H H H H H H
|
||||
distance = (H << 3) + D + 1
|
||||
|
||||
1 L L D D D S S (128..255)
|
||||
Copy 5-8 bytes from block within 2kB distance
|
||||
state = S (copy S literals after this block)
|
||||
length = 5 + L
|
||||
Always followed by exactly one byte : H H H H H H H H
|
||||
distance = (H << 3) + D + 1
|
||||
|
||||
Authors
|
||||
|
||||
This document was written by Willy Tarreau <w@1wt.eu> on 2014/07/19 during an
|
||||
analysis of the decompression code available in Linux 3.16-rc5. The code is
|
||||
tricky, it is possible that this document contains mistakes or that a few
|
||||
corner cases were overlooked. In any case, please report any doubt, fix, or
|
||||
proposed updates to the author(s) so that the document can be updated.
|
||||
122
Documentation/mailbox.txt
Normal file
122
Documentation/mailbox.txt
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
The Common Mailbox Framework
|
||||
Jassi Brar <jaswinder.singh@linaro.org>
|
||||
|
||||
This document aims to help developers write client and controller
|
||||
drivers for the API. But before we start, let us note that the
|
||||
client (especially) and controller drivers are likely going to be
|
||||
very platform specific because the remote firmware is likely to be
|
||||
proprietary and implement non-standard protocol. So even if two
|
||||
platforms employ, say, PL320 controller, the client drivers can't
|
||||
be shared across them. Even the PL320 driver might need to accommodate
|
||||
some platform specific quirks. So the API is meant mainly to avoid
|
||||
similar copies of code written for each platform. Having said that,
|
||||
nothing prevents the remote f/w to also be Linux based and use the
|
||||
same api there. However none of that helps us locally because we only
|
||||
ever deal at client's protocol level.
|
||||
Some of the choices made during implementation are the result of this
|
||||
peculiarity of this "common" framework.
|
||||
|
||||
|
||||
|
||||
Part 1 - Controller Driver (See include/linux/mailbox_controller.h)
|
||||
|
||||
Allocate mbox_controller and the array of mbox_chan.
|
||||
Populate mbox_chan_ops, except peek_data() all are mandatory.
|
||||
The controller driver might know a message has been consumed
|
||||
by the remote by getting an IRQ or polling some hardware flag
|
||||
or it can never know (the client knows by way of the protocol).
|
||||
The method in order of preference is IRQ -> Poll -> None, which
|
||||
the controller driver should set via 'txdone_irq' or 'txdone_poll'
|
||||
or neither.
|
||||
|
||||
|
||||
Part 2 - Client Driver (See include/linux/mailbox_client.h)
|
||||
|
||||
The client might want to operate in blocking mode (synchronously
|
||||
send a message through before returning) or non-blocking/async mode (submit
|
||||
a message and a callback function to the API and return immediately).
|
||||
|
||||
|
||||
struct demo_client {
|
||||
struct mbox_client cl;
|
||||
struct mbox_chan *mbox;
|
||||
struct completion c;
|
||||
bool async;
|
||||
/* ... */
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the handler for data received from remote. The behaviour is purely
|
||||
* dependent upon the protocol. This is just an example.
|
||||
*/
|
||||
static void message_from_remote(struct mbox_client *cl, void *mssg)
|
||||
{
|
||||
struct demo_client *dc = container_of(mbox_client,
|
||||
struct demo_client, cl);
|
||||
if (dc->aysnc) {
|
||||
if (is_an_ack(mssg)) {
|
||||
/* An ACK to our last sample sent */
|
||||
return; /* Or do something else here */
|
||||
} else { /* A new message from remote */
|
||||
queue_req(mssg);
|
||||
}
|
||||
} else {
|
||||
/* Remote f/w sends only ACK packets on this channel */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void sample_sent(struct mbox_client *cl, void *mssg, int r)
|
||||
{
|
||||
struct demo_client *dc = container_of(mbox_client,
|
||||
struct demo_client, cl);
|
||||
complete(&dc->c);
|
||||
}
|
||||
|
||||
static void client_demo(struct platform_device *pdev)
|
||||
{
|
||||
struct demo_client *dc_sync, *dc_async;
|
||||
/* The controller already knows async_pkt and sync_pkt */
|
||||
struct async_pkt ap;
|
||||
struct sync_pkt sp;
|
||||
|
||||
dc_sync = kzalloc(sizeof(*dc_sync), GFP_KERNEL);
|
||||
dc_async = kzalloc(sizeof(*dc_async), GFP_KERNEL);
|
||||
|
||||
/* Populate non-blocking mode client */
|
||||
dc_async->cl.dev = &pdev->dev;
|
||||
dc_async->cl.rx_callback = message_from_remote;
|
||||
dc_async->cl.tx_done = sample_sent;
|
||||
dc_async->cl.tx_block = false;
|
||||
dc_async->cl.tx_tout = 0; /* doesn't matter here */
|
||||
dc_async->cl.knows_txdone = false; /* depending upon protocol */
|
||||
dc_async->async = true;
|
||||
init_completion(&dc_async->c);
|
||||
|
||||
/* Populate blocking mode client */
|
||||
dc_sync->cl.dev = &pdev->dev;
|
||||
dc_sync->cl.rx_callback = message_from_remote;
|
||||
dc_sync->cl.tx_done = NULL; /* operate in blocking mode */
|
||||
dc_sync->cl.tx_block = true;
|
||||
dc_sync->cl.tx_tout = 500; /* by half a second */
|
||||
dc_sync->cl.knows_txdone = false; /* depending upon protocol */
|
||||
dc_sync->async = false;
|
||||
|
||||
/* ASync mailbox is listed second in 'mboxes' property */
|
||||
dc_async->mbox = mbox_request_channel(&dc_async->cl, 1);
|
||||
/* Populate data packet */
|
||||
/* ap.xxx = 123; etc */
|
||||
/* Send async message to remote */
|
||||
mbox_send_message(dc_async->mbox, &ap);
|
||||
|
||||
/* Sync mailbox is listed first in 'mboxes' property */
|
||||
dc_sync->mbox = mbox_request_channel(&dc_sync->cl, 0);
|
||||
/* Populate data packet */
|
||||
/* sp.abc = 123; etc */
|
||||
/* Send message to remote in blocking mode */
|
||||
mbox_send_message(dc_sync->mbox, &sp);
|
||||
/* At this point 'sp' has been sent */
|
||||
|
||||
/* Now wait for async chan to be done */
|
||||
wait_for_completion(&dc_async->c);
|
||||
}
|
||||
|
|
@ -1339,6 +1339,19 @@ ndisc_notify - BOOLEAN
|
|||
1 - Generate unsolicited neighbour advertisements when device is brought
|
||||
up or hardware address changes.
|
||||
|
||||
optimistic_dad - BOOLEAN
|
||||
Whether to perform Optimistic Duplicate Address Detection (RFC 4429).
|
||||
0: disabled (default)
|
||||
1: enabled
|
||||
|
||||
use_optimistic - BOOLEAN
|
||||
If enabled, do not classify optimistic addresses as deprecated during
|
||||
source address selection. Preferred addresses will still be chosen
|
||||
before optimistic addresses, subject to other ranking in the source
|
||||
address selection algorithm.
|
||||
0: disabled (default)
|
||||
1: enabled
|
||||
|
||||
icmp/*:
|
||||
ratelimit - INTEGER
|
||||
Limit the maximal rates for sending ICMPv6 packets.
|
||||
|
|
|
|||
|
|
@ -2026,8 +2026,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
|||
-------------------
|
||||
|
||||
Module for sound cards based on the Asus AV66/AV100/AV200 chips,
|
||||
i.e., Xonar D1, DX, D2, D2X, DS, Essence ST (Deluxe), Essence STX,
|
||||
HDAV1.3 (Deluxe), and HDAV1.3 Slim.
|
||||
i.e., Xonar D1, DX, D2, D2X, DS, DSX, Essence ST (Deluxe),
|
||||
Essence STX (II), HDAV1.3 (Deluxe), and HDAV1.3 Slim.
|
||||
|
||||
This module supports autoprobe and multiple cards.
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ Rules on what kind of patches are accepted, and which ones are not, into the
|
|||
|
||||
Procedure for submitting patches to the -stable tree:
|
||||
|
||||
- If the patch covers files in net/ or drivers/net please follow netdev stable
|
||||
submission guidelines as described in
|
||||
Documentation/networking/netdev-FAQ.txt
|
||||
- Send the patch, after verifying that it follows the above rules, to
|
||||
stable@vger.kernel.org. You must note the upstream commit ID in the
|
||||
changelog of your submission, as well as the kernel version you wish
|
||||
|
|
|
|||
|
|
@ -148,9 +148,9 @@ of banks, as set via the KVM_X86_SETUP_MCE ioctl.
|
|||
|
||||
4.4 KVM_CHECK_EXTENSION
|
||||
|
||||
Capability: basic
|
||||
Capability: basic, KVM_CAP_CHECK_EXTENSION_VM for vm ioctl
|
||||
Architectures: all
|
||||
Type: system ioctl
|
||||
Type: system ioctl, vm ioctl
|
||||
Parameters: extension identifier (KVM_CAP_*)
|
||||
Returns: 0 if unsupported; 1 (or some other positive integer) if supported
|
||||
|
||||
|
|
@ -160,6 +160,9 @@ receives an integer that describes the extension availability.
|
|||
Generally 0 means no and 1 means yes, but some extensions may report
|
||||
additional information in the integer return value.
|
||||
|
||||
Based on their initialization different VMs may have different capabilities.
|
||||
It is thus encouraged to use the vm ioctl to query for capabilities (available
|
||||
with KVM_CAP_CHECK_EXTENSION_VM on the vm fd)
|
||||
|
||||
4.5 KVM_GET_VCPU_MMAP_SIZE
|
||||
|
||||
|
|
@ -280,7 +283,7 @@ kvm_run' (see below).
|
|||
4.11 KVM_GET_REGS
|
||||
|
||||
Capability: basic
|
||||
Architectures: all except ARM
|
||||
Architectures: all except ARM, arm64
|
||||
Type: vcpu ioctl
|
||||
Parameters: struct kvm_regs (out)
|
||||
Returns: 0 on success, -1 on error
|
||||
|
|
@ -301,7 +304,7 @@ struct kvm_regs {
|
|||
4.12 KVM_SET_REGS
|
||||
|
||||
Capability: basic
|
||||
Architectures: all except ARM
|
||||
Architectures: all except ARM, arm64
|
||||
Type: vcpu ioctl
|
||||
Parameters: struct kvm_regs (in)
|
||||
Returns: 0 on success, -1 on error
|
||||
|
|
@ -587,7 +590,7 @@ struct kvm_fpu {
|
|||
4.24 KVM_CREATE_IRQCHIP
|
||||
|
||||
Capability: KVM_CAP_IRQCHIP
|
||||
Architectures: x86, ia64, ARM
|
||||
Architectures: x86, ia64, ARM, arm64
|
||||
Type: vm ioctl
|
||||
Parameters: none
|
||||
Returns: 0 on success, -1 on error
|
||||
|
|
@ -595,14 +598,14 @@ Returns: 0 on success, -1 on error
|
|||
Creates an interrupt controller model in the kernel. On x86, creates a virtual
|
||||
ioapic, a virtual PIC (two PICs, nested), and sets up future vcpus to have a
|
||||
local APIC. IRQ routing for GSIs 0-15 is set to both PIC and IOAPIC; GSI 16-23
|
||||
only go to the IOAPIC. On ia64, a IOSAPIC is created. On ARM, a GIC is
|
||||
only go to the IOAPIC. On ia64, a IOSAPIC is created. On ARM/arm64, a GIC is
|
||||
created.
|
||||
|
||||
|
||||
4.25 KVM_IRQ_LINE
|
||||
|
||||
Capability: KVM_CAP_IRQCHIP
|
||||
Architectures: x86, ia64, arm
|
||||
Architectures: x86, ia64, arm, arm64
|
||||
Type: vm ioctl
|
||||
Parameters: struct kvm_irq_level
|
||||
Returns: 0 on success, -1 on error
|
||||
|
|
@ -612,9 +615,10 @@ On some architectures it is required that an interrupt controller model has
|
|||
been previously created with KVM_CREATE_IRQCHIP. Note that edge-triggered
|
||||
interrupts require the level to be set to 1 and then back to 0.
|
||||
|
||||
ARM can signal an interrupt either at the CPU level, or at the in-kernel irqchip
|
||||
(GIC), and for in-kernel irqchip can tell the GIC to use PPIs designated for
|
||||
specific cpus. The irq field is interpreted like this:
|
||||
ARM/arm64 can signal an interrupt either at the CPU level, or at the
|
||||
in-kernel irqchip (GIC), and for in-kernel irqchip can tell the GIC to
|
||||
use PPIs designated for specific cpus. The irq field is interpreted
|
||||
like this:
|
||||
|
||||
bits: | 31 ... 24 | 23 ... 16 | 15 ... 0 |
|
||||
field: | irq_type | vcpu_index | irq_id |
|
||||
|
|
@ -968,18 +972,20 @@ uniprocessor guests).
|
|||
|
||||
Possible values are:
|
||||
|
||||
- KVM_MP_STATE_RUNNABLE: the vcpu is currently running
|
||||
- KVM_MP_STATE_RUNNABLE: the vcpu is currently running [x86, ia64]
|
||||
- KVM_MP_STATE_UNINITIALIZED: the vcpu is an application processor (AP)
|
||||
which has not yet received an INIT signal
|
||||
which has not yet received an INIT signal [x86,
|
||||
ia64]
|
||||
- KVM_MP_STATE_INIT_RECEIVED: the vcpu has received an INIT signal, and is
|
||||
now ready for a SIPI
|
||||
now ready for a SIPI [x86, ia64]
|
||||
- KVM_MP_STATE_HALTED: the vcpu has executed a HLT instruction and
|
||||
is waiting for an interrupt
|
||||
is waiting for an interrupt [x86, ia64]
|
||||
- KVM_MP_STATE_SIPI_RECEIVED: the vcpu has just received a SIPI (vector
|
||||
accessible via KVM_GET_VCPU_EVENTS)
|
||||
accessible via KVM_GET_VCPU_EVENTS) [x86, ia64]
|
||||
|
||||
This ioctl is only useful after KVM_CREATE_IRQCHIP. Without an in-kernel
|
||||
irqchip, the multiprocessing state must be maintained by userspace.
|
||||
On x86 and ia64, this ioctl is only useful after KVM_CREATE_IRQCHIP. Without an
|
||||
in-kernel irqchip, the multiprocessing state must be maintained by userspace on
|
||||
these architectures.
|
||||
|
||||
|
||||
4.39 KVM_SET_MP_STATE
|
||||
|
|
@ -993,8 +999,9 @@ Returns: 0 on success; -1 on error
|
|||
Sets the vcpu's current "multiprocessing state"; see KVM_GET_MP_STATE for
|
||||
arguments.
|
||||
|
||||
This ioctl is only useful after KVM_CREATE_IRQCHIP. Without an in-kernel
|
||||
irqchip, the multiprocessing state must be maintained by userspace.
|
||||
On x86 and ia64, this ioctl is only useful after KVM_CREATE_IRQCHIP. Without an
|
||||
in-kernel irqchip, the multiprocessing state must be maintained by userspace on
|
||||
these architectures.
|
||||
|
||||
|
||||
4.40 KVM_SET_IDENTITY_MAP_ADDR
|
||||
|
|
@ -1121,9 +1128,9 @@ struct kvm_cpuid2 {
|
|||
struct kvm_cpuid_entry2 entries[0];
|
||||
};
|
||||
|
||||
#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX 1
|
||||
#define KVM_CPUID_FLAG_STATEFUL_FUNC 2
|
||||
#define KVM_CPUID_FLAG_STATE_READ_NEXT 4
|
||||
#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)
|
||||
|
||||
struct kvm_cpuid_entry2 {
|
||||
__u32 function;
|
||||
|
|
@ -1831,6 +1838,22 @@ ARM 32-bit VFP control registers have the following id bit patterns:
|
|||
ARM 64-bit FP registers have the following id bit patterns:
|
||||
0x4030 0000 0012 0 <regno:12>
|
||||
|
||||
|
||||
arm64 registers are mapped using the lower 32 bits. The upper 16 of
|
||||
that is the register group type, or coprocessor number:
|
||||
|
||||
arm64 core/FP-SIMD registers have the following id bit patterns. Note
|
||||
that the size of the access is variable, as the kvm_regs structure
|
||||
contains elements ranging from 32 to 128 bits. The index is a 32bit
|
||||
value in the kvm_regs structure seen as a 32bit array.
|
||||
0x60x0 0000 0010 <index into the kvm_regs struct:16>
|
||||
|
||||
arm64 CCSIDR registers are demultiplexed by CSSELR value:
|
||||
0x6020 0000 0011 00 <csselr:8>
|
||||
|
||||
arm64 system registers have the following id bit patterns:
|
||||
0x6030 0000 0013 <op0:2> <op1:3> <crn:4> <crm:4> <op2:3>
|
||||
|
||||
4.69 KVM_GET_ONE_REG
|
||||
|
||||
Capability: KVM_CAP_ONE_REG
|
||||
|
|
@ -2264,7 +2287,7 @@ current state. "addr" is ignored.
|
|||
4.77 KVM_ARM_VCPU_INIT
|
||||
|
||||
Capability: basic
|
||||
Architectures: arm
|
||||
Architectures: arm, arm64
|
||||
Type: vcpu ioctl
|
||||
Parameters: struct struct kvm_vcpu_init (in)
|
||||
Returns: 0 on success; -1 on error
|
||||
|
|
@ -2283,12 +2306,14 @@ should be created before this ioctl is invoked.
|
|||
Possible features:
|
||||
- KVM_ARM_VCPU_POWER_OFF: Starts the CPU in a power-off state.
|
||||
Depends on KVM_CAP_ARM_PSCI.
|
||||
- KVM_ARM_VCPU_EL1_32BIT: Starts the CPU in a 32bit mode.
|
||||
Depends on KVM_CAP_ARM_EL1_32BIT (arm64 only).
|
||||
|
||||
|
||||
4.78 KVM_GET_REG_LIST
|
||||
|
||||
Capability: basic
|
||||
Architectures: arm
|
||||
Architectures: arm, arm64
|
||||
Type: vcpu ioctl
|
||||
Parameters: struct kvm_reg_list (in/out)
|
||||
Returns: 0 on success; -1 on error
|
||||
|
|
@ -2305,10 +2330,10 @@ This ioctl returns the guest registers that are supported for the
|
|||
KVM_GET_ONE_REG/KVM_SET_ONE_REG calls.
|
||||
|
||||
|
||||
4.80 KVM_ARM_SET_DEVICE_ADDR
|
||||
4.85 KVM_ARM_SET_DEVICE_ADDR (deprecated)
|
||||
|
||||
Capability: KVM_CAP_ARM_SET_DEVICE_ADDR
|
||||
Architectures: arm
|
||||
Architectures: arm, arm64
|
||||
Type: vm ioctl
|
||||
Parameters: struct kvm_arm_device_address (in)
|
||||
Returns: 0 on success, -1 on error
|
||||
|
|
@ -2329,20 +2354,25 @@ can access emulated or directly exposed devices, which the host kernel needs
|
|||
to know about. The id field is an architecture specific identifier for a
|
||||
specific device.
|
||||
|
||||
ARM divides the id field into two parts, a device id and an address type id
|
||||
specific to the individual device.
|
||||
ARM/arm64 divides the id field into two parts, a device id and an
|
||||
address type id specific to the individual device.
|
||||
|
||||
bits: | 63 ... 32 | 31 ... 16 | 15 ... 0 |
|
||||
field: | 0x00000000 | device id | addr type id |
|
||||
|
||||
ARM currently only require this when using the in-kernel GIC support for the
|
||||
hardware VGIC features, using KVM_ARM_DEVICE_VGIC_V2 as the device id. When
|
||||
setting the base address for the guest's mapping of the VGIC virtual CPU
|
||||
and distributor interface, the ioctl must be called after calling
|
||||
KVM_CREATE_IRQCHIP, but before calling KVM_RUN on any of the VCPUs. Calling
|
||||
this ioctl twice for any of the base addresses will return -EEXIST.
|
||||
ARM/arm64 currently only require this when using the in-kernel GIC
|
||||
support for the hardware VGIC features, using KVM_ARM_DEVICE_VGIC_V2
|
||||
as the device id. When setting the base address for the guest's
|
||||
mapping of the VGIC virtual CPU and distributor interface, the ioctl
|
||||
must be called after calling KVM_CREATE_IRQCHIP, but before calling
|
||||
KVM_RUN on any of the VCPUs. Calling this ioctl twice for any of the
|
||||
base addresses will return -EEXIST.
|
||||
|
||||
4.82 KVM_PPC_RTAS_DEFINE_TOKEN
|
||||
Note, this IOCTL is deprecated and the more flexible SET/GET_DEVICE_ATTR API
|
||||
should be used instead.
|
||||
|
||||
|
||||
4.86 KVM_PPC_RTAS_DEFINE_TOKEN
|
||||
|
||||
Capability: KVM_CAP_PPC_RTAS
|
||||
Architectures: ppc
|
||||
|
|
@ -2612,6 +2642,21 @@ It gets triggered whenever both KVM_CAP_PPC_EPR are enabled and an
|
|||
external interrupt has just been delivered into the guest. User space
|
||||
should put the acknowledged interrupt vector into the 'epr' field.
|
||||
|
||||
/* KVM_EXIT_SYSTEM_EVENT */
|
||||
struct {
|
||||
#define KVM_SYSTEM_EVENT_SHUTDOWN 1
|
||||
#define KVM_SYSTEM_EVENT_RESET 2
|
||||
__u32 type;
|
||||
__u64 flags;
|
||||
} system_event;
|
||||
|
||||
If exit_reason is KVM_EXIT_SYSTEM_EVENT then the vcpu has triggered
|
||||
a system-level event using some architecture specific mechanism (hypercall
|
||||
or some special instruction). In case of ARM/ARM64, this is triggered using
|
||||
HVC instruction based PSCI call from the vcpu. The 'type' field describes
|
||||
the system-level event type. The 'flags' field describes architecture
|
||||
specific flags for the system-level event.
|
||||
|
||||
/* Fix the size of the union. */
|
||||
char padding[256];
|
||||
};
|
||||
|
|
@ -2641,6 +2686,77 @@ and usually define the validity of a groups of registers. (e.g. one bit
|
|||
};
|
||||
|
||||
|
||||
4.81 KVM_GET_EMULATED_CPUID
|
||||
|
||||
Capability: KVM_CAP_EXT_EMUL_CPUID
|
||||
Architectures: x86
|
||||
Type: system ioctl
|
||||
Parameters: struct kvm_cpuid2 (in/out)
|
||||
Returns: 0 on success, -1 on error
|
||||
|
||||
struct kvm_cpuid2 {
|
||||
__u32 nent;
|
||||
__u32 flags;
|
||||
struct kvm_cpuid_entry2 entries[0];
|
||||
};
|
||||
|
||||
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)
|
||||
|
||||
struct kvm_cpuid_entry2 {
|
||||
__u32 function;
|
||||
__u32 index;
|
||||
__u32 flags;
|
||||
__u32 eax;
|
||||
__u32 ebx;
|
||||
__u32 ecx;
|
||||
__u32 edx;
|
||||
__u32 padding[3];
|
||||
};
|
||||
|
||||
This ioctl returns x86 cpuid features which are emulated by
|
||||
kvm.Userspace can use the information returned by this ioctl to query
|
||||
which features are emulated by kvm instead of being present natively.
|
||||
|
||||
Userspace invokes KVM_GET_EMULATED_CPUID by passing a kvm_cpuid2
|
||||
structure with the 'nent' field indicating the number of entries in
|
||||
the variable-size array 'entries'. If the number of entries is too low
|
||||
to describe the cpu capabilities, an error (E2BIG) is returned. If the
|
||||
number is too high, the 'nent' field is adjusted and an error (ENOMEM)
|
||||
is returned. If the number is just right, the 'nent' field is adjusted
|
||||
to the number of valid entries in the 'entries' array, which is then
|
||||
filled.
|
||||
|
||||
The entries returned are the set CPUID bits of the respective features
|
||||
which kvm emulates, as returned by the CPUID instruction, with unknown
|
||||
or unsupported feature bits cleared.
|
||||
|
||||
Features like x2apic, for example, may not be present in the host cpu
|
||||
but are exposed by kvm in KVM_GET_SUPPORTED_CPUID because they can be
|
||||
emulated efficiently and thus not included here.
|
||||
|
||||
The fields in each entry are defined as follows:
|
||||
|
||||
function: the eax value used to obtain the entry
|
||||
index: the ecx value used to obtain the entry (for entries that are
|
||||
affected by ecx)
|
||||
flags: an OR of zero or more of the following:
|
||||
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
|
||||
this function/index combination
|
||||
|
||||
|
||||
6. Capabilities that can be enabled
|
||||
-----------------------------------
|
||||
|
||||
|
|
|
|||
83
Documentation/virtual/kvm/devices/arm-vgic.txt
Normal file
83
Documentation/virtual/kvm/devices/arm-vgic.txt
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
ARM Virtual Generic Interrupt Controller (VGIC)
|
||||
===============================================
|
||||
|
||||
Device types supported:
|
||||
KVM_DEV_TYPE_ARM_VGIC_V2 ARM Generic Interrupt Controller v2.0
|
||||
|
||||
Only one VGIC instance may be instantiated through either this API or the
|
||||
legacy KVM_CREATE_IRQCHIP api. The created VGIC will act as the VM interrupt
|
||||
controller, requiring emulated user-space devices to inject interrupts to the
|
||||
VGIC instead of directly to CPUs.
|
||||
|
||||
Groups:
|
||||
KVM_DEV_ARM_VGIC_GRP_ADDR
|
||||
Attributes:
|
||||
KVM_VGIC_V2_ADDR_TYPE_DIST (rw, 64-bit)
|
||||
Base address in the guest physical address space of the GIC distributor
|
||||
register mappings.
|
||||
|
||||
KVM_VGIC_V2_ADDR_TYPE_CPU (rw, 64-bit)
|
||||
Base address in the guest physical address space of the GIC virtual cpu
|
||||
interface register mappings.
|
||||
|
||||
KVM_DEV_ARM_VGIC_GRP_DIST_REGS
|
||||
Attributes:
|
||||
The attr field of kvm_device_attr encodes two values:
|
||||
bits: | 63 .... 40 | 39 .. 32 | 31 .... 0 |
|
||||
values: | reserved | cpu id | offset |
|
||||
|
||||
All distributor regs are (rw, 32-bit)
|
||||
|
||||
The offset is relative to the "Distributor base address" as defined in the
|
||||
GICv2 specs. Getting or setting such a register has the same effect as
|
||||
reading or writing the register on the actual hardware from the cpu
|
||||
specified with cpu id field. Note that most distributor fields are not
|
||||
banked, but return the same value regardless of the cpu id used to access
|
||||
the register.
|
||||
Limitations:
|
||||
- Priorities are not implemented, and registers are RAZ/WI
|
||||
Errors:
|
||||
-ENODEV: Getting or setting this register is not yet supported
|
||||
-EBUSY: One or more VCPUs are running
|
||||
|
||||
KVM_DEV_ARM_VGIC_GRP_CPU_REGS
|
||||
Attributes:
|
||||
The attr field of kvm_device_attr encodes two values:
|
||||
bits: | 63 .... 40 | 39 .. 32 | 31 .... 0 |
|
||||
values: | reserved | cpu id | offset |
|
||||
|
||||
All CPU interface regs are (rw, 32-bit)
|
||||
|
||||
The offset specifies the offset from the "CPU interface base address" as
|
||||
defined in the GICv2 specs. Getting or setting such a register has the
|
||||
same effect as reading or writing the register on the actual hardware.
|
||||
|
||||
The Active Priorities Registers APRn are implementation defined, so we set a
|
||||
fixed format for our implementation that fits with the model of a "GICv2
|
||||
implementation without the security extensions" which we present to the
|
||||
guest. This interface always exposes four register APR[0-3] describing the
|
||||
maximum possible 128 preemption levels. The semantics of the register
|
||||
indicate if any interrupts in a given preemption level are in the active
|
||||
state by setting the corresponding bit.
|
||||
|
||||
Thus, preemption level X has one or more active interrupts if and only if:
|
||||
|
||||
APRn[X mod 32] == 0b1, where n = X / 32
|
||||
|
||||
Bits for undefined preemption levels are RAZ/WI.
|
||||
|
||||
Limitations:
|
||||
- Priorities are not implemented, and registers are RAZ/WI
|
||||
Errors:
|
||||
-ENODEV: Getting or setting this register is not yet supported
|
||||
-EBUSY: One or more VCPUs are running
|
||||
|
||||
KVM_DEV_ARM_VGIC_GRP_NR_IRQS
|
||||
Attributes:
|
||||
A value describing the number of interrupts (SGI, PPI and SPI) for
|
||||
this GIC instance, ranging from 64 to 1024, in increments of 32.
|
||||
|
||||
Errors:
|
||||
-EINVAL: Value set is out of the expected range
|
||||
-EBUSY: Value has already be set, or GIC has already been initialized
|
||||
with default values.
|
||||
22
Documentation/virtual/kvm/devices/vfio.txt
Normal file
22
Documentation/virtual/kvm/devices/vfio.txt
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
VFIO virtual device
|
||||
===================
|
||||
|
||||
Device types supported:
|
||||
KVM_DEV_TYPE_VFIO
|
||||
|
||||
Only one VFIO instance may be created per VM. The created device
|
||||
tracks VFIO groups in use by the VM and features of those groups
|
||||
important to the correctness and acceleration of the VM. As groups
|
||||
are enabled and disabled for use by the VM, KVM should be updated
|
||||
about their presence. When registered with KVM, a reference to the
|
||||
VFIO-group is held by KVM.
|
||||
|
||||
Groups:
|
||||
KVM_DEV_VFIO_GROUP
|
||||
|
||||
KVM_DEV_VFIO_GROUP attributes:
|
||||
KVM_DEV_VFIO_GROUP_ADD: Add a VFIO group to VFIO-KVM device tracking
|
||||
KVM_DEV_VFIO_GROUP_DEL: Remove a VFIO group from VFIO-KVM device tracking
|
||||
|
||||
For each, kvm_device_attr.addr points to an int32_t file descriptor
|
||||
for the VFIO group.
|
||||
|
|
@ -132,10 +132,14 @@ See the comments in spte_has_volatile_bits() and mmu_spte_update().
|
|||
------------
|
||||
|
||||
Name: kvm_lock
|
||||
Type: raw_spinlock
|
||||
Type: spinlock_t
|
||||
Arch: any
|
||||
Protects: - vm_list
|
||||
- hardware virtualization enable/disable
|
||||
|
||||
Name: kvm_count_lock
|
||||
Type: raw_spinlock_t
|
||||
Arch: any
|
||||
Protects: - hardware virtualization enable/disable
|
||||
Comment: 'raw' because hardware enabling/disabling must be atomic /wrt
|
||||
migration.
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ ffffc90000000000 - ffffe8ffffffffff (=45 bits) vmalloc/ioremap space
|
|||
ffffe90000000000 - ffffe9ffffffffff (=40 bits) hole
|
||||
ffffea0000000000 - ffffeaffffffffff (=40 bits) virtual memory map (1TB)
|
||||
... unused hole ...
|
||||
ffffff0000000000 - ffffff7fffffffff (=39 bits) %esp fixup stacks
|
||||
... unused hole ...
|
||||
ffffffff80000000 - ffffffffa0000000 (=512 MB) kernel text mapping, from phys 0
|
||||
ffffffffa0000000 - ffffffffff5fffff (=1525 MB) module mapping space
|
||||
ffffffffff600000 - ffffffffffdfffff (=8 MB) vsyscalls
|
||||
|
|
|
|||
|
|
@ -4719,6 +4719,15 @@ F: arch/arm/include/uapi/asm/kvm*
|
|||
F: arch/arm/include/asm/kvm*
|
||||
F: arch/arm/kvm/
|
||||
|
||||
KERNEL VIRTUAL MACHINE FOR ARM64 (KVM/arm64)
|
||||
M: Marc Zyngier <marc.zyngier@arm.com>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
L: kvmarm@lists.cs.columbia.edu
|
||||
S: Maintained
|
||||
F: arch/arm64/include/uapi/asm/kvm*
|
||||
F: arch/arm64/include/asm/kvm*
|
||||
F: arch/arm64/kvm/
|
||||
|
||||
KEXEC
|
||||
M: Eric Biederman <ebiederm@xmission.com>
|
||||
W: http://kernel.org/pub/linux/utils/kernel/kexec/
|
||||
|
|
|
|||
4
Makefile
4
Makefile
|
|
@ -1,6 +1,6 @@
|
|||
VERSION = 3
|
||||
PATCHLEVEL = 10
|
||||
SUBLEVEL = 49
|
||||
SUBLEVEL = 61
|
||||
EXTRAVERSION =
|
||||
NAME = TOSSUG Baby Fish
|
||||
|
||||
|
|
@ -626,6 +626,8 @@ KBUILD_CFLAGS += -fomit-frame-pointer
|
|||
endif
|
||||
endif
|
||||
|
||||
KBUILD_CFLAGS += $(call cc-option, -fno-var-tracking-assignments)
|
||||
|
||||
ifdef CONFIG_DEBUG_INFO
|
||||
KBUILD_CFLAGS += -g
|
||||
KBUILD_AFLAGS += -gdwarf-2
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ CONFIG_ANDROID=y
|
|||
CONFIG_ANDROID_BINDER_IPC=y
|
||||
CONFIG_ANDROID_INTF_ALARM_DEV=y
|
||||
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
|
||||
CONFIG_ARMV7_COMPAT=y
|
||||
CONFIG_ASHMEM=y
|
||||
CONFIG_BLK_DEV_DM=y
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
|
|
@ -24,6 +25,7 @@ CONFIG_INET6_ESP=y
|
|||
CONFIG_INET6_IPCOMP=y
|
||||
CONFIG_INET=y
|
||||
CONFIG_INET_ESP=y
|
||||
CONFIG_INET_XFRM_MODE_TUNNEL=y
|
||||
CONFIG_IP6_NF_FILTER=y
|
||||
CONFIG_IP6_NF_IPTABLES=y
|
||||
CONFIG_IP6_NF_MANGLE=y
|
||||
|
|
|
|||
|
|
@ -331,6 +331,7 @@ config HAVE_ARCH_SECCOMP_FILTER
|
|||
- secure_computing is called from a ptrace_event()-safe context
|
||||
- secure_computing return value is checked and a return value of -1
|
||||
results in the system call being skipped immediately.
|
||||
- seccomp syscall wired up
|
||||
|
||||
config SECCOMP_FILTER
|
||||
def_bool y
|
||||
|
|
|
|||
|
|
@ -89,8 +89,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
|
|||
const struct exception_table_entry *fixup;
|
||||
int fault, si_code = SEGV_MAPERR;
|
||||
siginfo_t info;
|
||||
unsigned int flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
|
||||
(cause > 0 ? FAULT_FLAG_WRITE : 0));
|
||||
unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
|
||||
|
||||
/* 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
|
||||
|
|
@ -115,7 +114,8 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
|
|||
if (address >= TASK_SIZE)
|
||||
goto vmalloc_fault;
|
||||
#endif
|
||||
|
||||
if (user_mode(regs))
|
||||
flags |= FAULT_FLAG_USER;
|
||||
retry:
|
||||
down_read(&mm->mmap_sem);
|
||||
vma = find_vma(mm, address);
|
||||
|
|
@ -142,6 +142,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
|
|||
} else {
|
||||
if (!(vma->vm_flags & VM_WRITE))
|
||||
goto bad_area;
|
||||
flags |= FAULT_FLAG_WRITE;
|
||||
}
|
||||
|
||||
/* If for any reason at all we couldn't handle the fault,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ chosen {
|
|||
/* this is for console on PGU */
|
||||
/* bootargs = "console=tty0 consoleblank=0"; */
|
||||
/* this is for console on serial */
|
||||
bootargs = "earlycon=uart8250,mmio32,0xc0000000,115200n8 console=ttyS0,115200n8 consoleblank=0 debug";
|
||||
bootargs = "earlycon=uart8250,mmio32,0xc0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblank=0 debug";
|
||||
};
|
||||
|
||||
aliases {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
* register API yet */
|
||||
#undef DBG_MAX_REG_NUM
|
||||
|
||||
#define GDB_MAX_REGS 39
|
||||
#define GDB_MAX_REGS 87
|
||||
|
||||
#define BREAK_INSTR_SIZE 2
|
||||
#define CACHE_FLUSH_IS_SAFE 1
|
||||
|
|
@ -33,23 +33,27 @@ static inline void arch_kgdb_breakpoint(void)
|
|||
|
||||
extern void kgdb_trap(struct pt_regs *regs, int param);
|
||||
|
||||
enum arc700_linux_regnums {
|
||||
/* This is the numbering of registers according to the GDB. See GDB's
|
||||
* arc-tdep.h for details.
|
||||
*
|
||||
* Registers are ordered for GDB 7.5. It is incompatible with GDB 6.8. */
|
||||
enum arc_linux_regnums {
|
||||
_R0 = 0,
|
||||
_R1, _R2, _R3, _R4, _R5, _R6, _R7, _R8, _R9, _R10, _R11, _R12, _R13,
|
||||
_R14, _R15, _R16, _R17, _R18, _R19, _R20, _R21, _R22, _R23, _R24,
|
||||
_R25, _R26,
|
||||
_BTA = 27,
|
||||
_LP_START = 28,
|
||||
_LP_END = 29,
|
||||
_LP_COUNT = 30,
|
||||
_STATUS32 = 31,
|
||||
_BLINK = 32,
|
||||
_FP = 33,
|
||||
__SP = 34,
|
||||
_EFA = 35,
|
||||
_RET = 36,
|
||||
_ORIG_R8 = 37,
|
||||
_STOP_PC = 38
|
||||
_FP = 27,
|
||||
__SP = 28,
|
||||
_R30 = 30,
|
||||
_BLINK = 31,
|
||||
_LP_COUNT = 60,
|
||||
_STOP_PC = 64,
|
||||
_RET = 64,
|
||||
_LP_START = 65,
|
||||
_LP_END = 66,
|
||||
_STATUS32 = 67,
|
||||
_ECR = 76,
|
||||
_BTA = 82,
|
||||
};
|
||||
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#ifndef _UAPI__ASM_ARC_PTRACE_H
|
||||
#define _UAPI__ASM_ARC_PTRACE_H
|
||||
|
||||
#define PTRACE_GET_THREAD_AREA 25
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -136,6 +136,10 @@ long arch_ptrace(struct task_struct *child, long request,
|
|||
pr_debug("REQ=%ld: ADDR =0x%lx, DATA=0x%lx)\n", request, addr, data);
|
||||
|
||||
switch (request) {
|
||||
case PTRACE_GET_THREAD_AREA:
|
||||
ret = put_user(task_thread_info(child)->thr_ptr,
|
||||
(unsigned long __user *)data);
|
||||
break;
|
||||
default:
|
||||
ret = ptrace_request(child, request, addr, data);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -59,8 +59,7 @@ void do_page_fault(struct pt_regs *regs, int write, unsigned long address,
|
|||
struct mm_struct *mm = tsk->mm;
|
||||
siginfo_t info;
|
||||
int fault, ret;
|
||||
unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
|
||||
(write ? FAULT_FLAG_WRITE : 0);
|
||||
unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
|
||||
|
||||
/*
|
||||
* We fault-in kernel-space virtual memory on-demand. The
|
||||
|
|
@ -88,6 +87,8 @@ void do_page_fault(struct pt_regs *regs, int write, unsigned long address,
|
|||
if (in_atomic() || !mm)
|
||||
goto no_context;
|
||||
|
||||
if (user_mode(regs))
|
||||
flags |= FAULT_FLAG_USER;
|
||||
retry:
|
||||
down_read(&mm->mmap_sem);
|
||||
vma = find_vma(mm, address);
|
||||
|
|
@ -115,12 +116,12 @@ void do_page_fault(struct pt_regs *regs, int write, unsigned long address,
|
|||
if (write) {
|
||||
if (!(vma->vm_flags & VM_WRITE))
|
||||
goto bad_area;
|
||||
flags |= FAULT_FLAG_WRITE;
|
||||
} else {
|
||||
if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
|
||||
goto bad_area;
|
||||
}
|
||||
|
||||
survive:
|
||||
/*
|
||||
* If for any reason at all we couldn't handle the fault,
|
||||
* make sure we exit gracefully rather than endlessly redo
|
||||
|
|
@ -200,14 +201,12 @@ void do_page_fault(struct pt_regs *regs, int write, unsigned long address,
|
|||
die("Oops", regs, address, cause_code);
|
||||
|
||||
out_of_memory:
|
||||
if (is_global_init(tsk)) {
|
||||
yield();
|
||||
goto survive;
|
||||
}
|
||||
up_read(&mm->mmap_sem);
|
||||
|
||||
if (user_mode(regs))
|
||||
do_group_exit(SIGKILL); /* This will never return */
|
||||
if (user_mode(regs)) {
|
||||
pagefault_out_of_memory();
|
||||
return;
|
||||
}
|
||||
|
||||
goto no_context;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ config ARM
|
|||
select ARCH_BINFMT_ELF_RANDOMIZE_PIE
|
||||
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
|
||||
select ARCH_HAVE_CUSTOM_GPIO_H
|
||||
select ARCH_SUPPORTS_ATOMIC_RMW
|
||||
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
|
||||
select ARCH_WANT_IPC_PARSE_VERSION
|
||||
select BUILDTIME_EXTABLE_SORT if MMU
|
||||
|
|
@ -1877,6 +1878,14 @@ config HW_PERF_EVENTS
|
|||
Enable hardware performance counter support for perf events. If
|
||||
disabled, perf events will use software events only.
|
||||
|
||||
config SYS_SUPPORTS_HUGETLBFS
|
||||
def_bool y
|
||||
depends on ARM_LPAE
|
||||
|
||||
config HAVE_ARCH_TRANSPARENT_HUGEPAGE
|
||||
def_bool y
|
||||
depends on ARM_LPAE
|
||||
|
||||
source "mm/Kconfig"
|
||||
|
||||
config FORCE_MAX_ZONEORDER
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ CONFIG_SERIAL_SIRFSOC=y
|
|||
CONFIG_SERIAL_SIRFSOC_CONSOLE=y
|
||||
CONFIG_SERIAL_VT8500=y
|
||||
CONFIG_SERIAL_VT8500_CONSOLE=y
|
||||
CONFIG_SERIAL_XILINX_PS_UART=y
|
||||
CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y
|
||||
CONFIG_IPMI_HANDLER=y
|
||||
CONFIG_IPMI_SI=y
|
||||
CONFIG_I2C=y
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@
|
|||
* Endian independent macros for shifting bytes within registers.
|
||||
*/
|
||||
#ifndef __ARMEB__
|
||||
#define pull lsr
|
||||
#define push lsl
|
||||
#define lspull lsr
|
||||
#define lspush lsl
|
||||
#define get_byte_0 lsl #0
|
||||
#define get_byte_1 lsr #8
|
||||
#define get_byte_2 lsr #16
|
||||
|
|
@ -41,8 +41,8 @@
|
|||
#define put_byte_2 lsl #16
|
||||
#define put_byte_3 lsl #24
|
||||
#else
|
||||
#define pull lsl
|
||||
#define push lsr
|
||||
#define lspull lsl
|
||||
#define lspush lsr
|
||||
#define get_byte_0 lsr #24
|
||||
#define get_byte_1 lsr #16
|
||||
#define get_byte_2 lsr #8
|
||||
|
|
@ -219,9 +219,9 @@
|
|||
#ifdef CONFIG_SMP
|
||||
#if __LINUX_ARM_ARCH__ >= 7
|
||||
.ifeqs "\mode","arm"
|
||||
ALT_SMP(dmb)
|
||||
ALT_SMP(dmb ish)
|
||||
.else
|
||||
ALT_SMP(W(dmb))
|
||||
ALT_SMP(W(dmb) ish)
|
||||
.endif
|
||||
#elif __LINUX_ARM_ARCH__ == 6
|
||||
ALT_SMP(mcr p15, 0, r0, c7, c10, 5) @ dmb
|
||||
|
|
|
|||
|
|
@ -14,27 +14,27 @@
|
|||
#endif
|
||||
|
||||
#if __LINUX_ARM_ARCH__ >= 7
|
||||
#define isb() __asm__ __volatile__ ("isb" : : : "memory")
|
||||
#define dsb() __asm__ __volatile__ ("dsb" : : : "memory")
|
||||
#define dmb() __asm__ __volatile__ ("dmb" : : : "memory")
|
||||
#define isb(option) __asm__ __volatile__ ("isb " #option : : : "memory")
|
||||
#define dsb(option) __asm__ __volatile__ ("dsb " #option : : : "memory")
|
||||
#define dmb(option) __asm__ __volatile__ ("dmb " #option : : : "memory")
|
||||
#elif defined(CONFIG_CPU_XSC3) || __LINUX_ARM_ARCH__ == 6
|
||||
#define isb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
|
||||
#define isb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
|
||||
: : "r" (0) : "memory")
|
||||
#define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
|
||||
#define dsb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
|
||||
: : "r" (0) : "memory")
|
||||
#define dmb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \
|
||||
#define dmb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \
|
||||
: : "r" (0) : "memory")
|
||||
#elif defined(CONFIG_CPU_FA526)
|
||||
#define isb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
|
||||
#define isb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
|
||||
: : "r" (0) : "memory")
|
||||
#define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
|
||||
#define dsb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
|
||||
: : "r" (0) : "memory")
|
||||
#define dmb() __asm__ __volatile__ ("" : : : "memory")
|
||||
#define dmb(x) __asm__ __volatile__ ("" : : : "memory")
|
||||
#else
|
||||
#define isb() __asm__ __volatile__ ("" : : : "memory")
|
||||
#define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
|
||||
#define isb(x) __asm__ __volatile__ ("" : : : "memory")
|
||||
#define dsb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
|
||||
: : "r" (0) : "memory")
|
||||
#define dmb() __asm__ __volatile__ ("" : : : "memory")
|
||||
#define dmb(x) __asm__ __volatile__ ("" : : : "memory")
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_HAS_BARRIERS
|
||||
|
|
@ -42,7 +42,7 @@
|
|||
#elif defined(CONFIG_ARM_DMA_MEM_BUFFERABLE) || defined(CONFIG_SMP)
|
||||
#define mb() do { dsb(); outer_sync(); } while (0)
|
||||
#define rmb() dsb()
|
||||
#define wmb() mb()
|
||||
#define wmb() do { dsb(st); outer_sync(); } while (0)
|
||||
#else
|
||||
#define mb() barrier()
|
||||
#define rmb() barrier()
|
||||
|
|
@ -54,11 +54,26 @@
|
|||
#define smp_rmb() barrier()
|
||||
#define smp_wmb() barrier()
|
||||
#else
|
||||
#define smp_mb() dmb()
|
||||
#define smp_rmb() dmb()
|
||||
#define smp_wmb() dmb()
|
||||
#define smp_mb() dmb(ish)
|
||||
#define smp_rmb() smp_mb()
|
||||
#define smp_wmb() dmb(ishst)
|
||||
#endif
|
||||
|
||||
#define smp_store_release(p, v) \
|
||||
do { \
|
||||
compiletime_assert_atomic_type(*p); \
|
||||
smp_mb(); \
|
||||
ACCESS_ONCE(*p) = (v); \
|
||||
} while (0)
|
||||
|
||||
#define smp_load_acquire(p) \
|
||||
({ \
|
||||
typeof(*p) ___p1 = ACCESS_ONCE(*p); \
|
||||
compiletime_assert_atomic_type(*p); \
|
||||
smp_mb(); \
|
||||
___p1; \
|
||||
})
|
||||
|
||||
#define read_barrier_depends() do { } while(0)
|
||||
#define smp_read_barrier_depends() do { } while(0)
|
||||
|
||||
|
|
|
|||
|
|
@ -43,16 +43,18 @@
|
|||
#define ARM_CPU_IMP_ARM 0x41
|
||||
#define ARM_CPU_IMP_INTEL 0x69
|
||||
|
||||
#define ARM_CPU_PART_ARM1136 0xB360
|
||||
#define ARM_CPU_PART_ARM1156 0xB560
|
||||
#define ARM_CPU_PART_ARM1176 0xB760
|
||||
#define ARM_CPU_PART_ARM11MPCORE 0xB020
|
||||
#define ARM_CPU_PART_CORTEX_A8 0xC080
|
||||
#define ARM_CPU_PART_CORTEX_A9 0xC090
|
||||
#define ARM_CPU_PART_CORTEX_A5 0xC050
|
||||
#define ARM_CPU_PART_CORTEX_A15 0xC0F0
|
||||
#define ARM_CPU_PART_CORTEX_A7 0xC070
|
||||
#define ARM_CPU_PART_CORTEX_A12 0xC0D0
|
||||
/* ARM implemented processors */
|
||||
#define ARM_CPU_PART_ARM1136 0x4100b360
|
||||
#define ARM_CPU_PART_ARM1156 0x4100b560
|
||||
#define ARM_CPU_PART_ARM1176 0x4100b760
|
||||
#define ARM_CPU_PART_ARM11MPCORE 0x4100b020
|
||||
#define ARM_CPU_PART_CORTEX_A8 0x4100c080
|
||||
#define ARM_CPU_PART_CORTEX_A9 0x4100c090
|
||||
#define ARM_CPU_PART_CORTEX_A5 0x4100c050
|
||||
#define ARM_CPU_PART_CORTEX_A7 0x4100c070
|
||||
#define ARM_CPU_PART_CORTEX_A12 0x4100c0d0
|
||||
#define ARM_CPU_PART_CORTEX_A17 0x4100c0e0
|
||||
#define ARM_CPU_PART_CORTEX_A15 0x4100c0f0
|
||||
|
||||
#define ARM_CPU_XSCALE_ARCH_MASK 0xe000
|
||||
#define ARM_CPU_XSCALE_ARCH_V1 0x2000
|
||||
|
|
@ -123,14 +125,24 @@ static inline unsigned int __attribute_const__ read_cpuid_implementor(void)
|
|||
return (read_cpuid_id() & 0xFF000000) >> 24;
|
||||
}
|
||||
|
||||
static inline unsigned int __attribute_const__ read_cpuid_part_number(void)
|
||||
/*
|
||||
* The CPU part number is meaningless without referring to the CPU
|
||||
* implementer: implementers are free to define their own part numbers
|
||||
* which are permitted to clash with other implementer part numbers.
|
||||
*/
|
||||
static inline unsigned int __attribute_const__ read_cpuid_part(void)
|
||||
{
|
||||
return read_cpuid_id() & 0xff00fff0;
|
||||
}
|
||||
|
||||
static inline unsigned int __attribute_const__ __deprecated read_cpuid_part_number(void)
|
||||
{
|
||||
return read_cpuid_id() & 0xFFF0;
|
||||
}
|
||||
|
||||
static inline unsigned int __attribute_const__ xscale_cpu_arch_version(void)
|
||||
{
|
||||
return read_cpuid_part_number() & ARM_CPU_XSCALE_ARCH_MASK;
|
||||
return read_cpuid_id() & ARM_CPU_XSCALE_ARCH_MASK;
|
||||
}
|
||||
|
||||
static inline unsigned int __attribute_const__ read_cpuid_cachetype(void)
|
||||
|
|
|
|||
71
arch/arm/include/asm/hugetlb-3level.h
Normal file
71
arch/arm/include/asm/hugetlb-3level.h
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* arch/arm/include/asm/hugetlb-3level.h
|
||||
*
|
||||
* Copyright (C) 2012 ARM Ltd.
|
||||
*
|
||||
* Based on arch/x86/include/asm/hugetlb.h.
|
||||
*
|
||||
* 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _ASM_ARM_HUGETLB_3LEVEL_H
|
||||
#define _ASM_ARM_HUGETLB_3LEVEL_H
|
||||
|
||||
|
||||
/*
|
||||
* If our huge pte is non-zero then mark the valid bit.
|
||||
* This allows pte_present(huge_ptep_get(ptep)) to return true for non-zero
|
||||
* ptes.
|
||||
* (The valid bit is automatically cleared by set_pte_at for PROT_NONE ptes).
|
||||
*/
|
||||
static inline pte_t huge_ptep_get(pte_t *ptep)
|
||||
{
|
||||
pte_t retval = *ptep;
|
||||
if (pte_val(retval))
|
||||
pte_val(retval) |= L_PTE_VALID;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
|
||||
pte_t *ptep, pte_t pte)
|
||||
{
|
||||
set_pte_at(mm, addr, ptep, pte);
|
||||
}
|
||||
|
||||
static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
|
||||
unsigned long addr, pte_t *ptep)
|
||||
{
|
||||
ptep_clear_flush(vma, addr, ptep);
|
||||
}
|
||||
|
||||
static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
|
||||
unsigned long addr, pte_t *ptep)
|
||||
{
|
||||
ptep_set_wrprotect(mm, addr, ptep);
|
||||
}
|
||||
|
||||
static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
|
||||
unsigned long addr, pte_t *ptep)
|
||||
{
|
||||
return ptep_get_and_clear(mm, addr, ptep);
|
||||
}
|
||||
|
||||
static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
|
||||
unsigned long addr, pte_t *ptep,
|
||||
pte_t pte, int dirty)
|
||||
{
|
||||
return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
|
||||
}
|
||||
|
||||
#endif /* _ASM_ARM_HUGETLB_3LEVEL_H */
|
||||
84
arch/arm/include/asm/hugetlb.h
Normal file
84
arch/arm/include/asm/hugetlb.h
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* arch/arm/include/asm/hugetlb.h
|
||||
*
|
||||
* Copyright (C) 2012 ARM Ltd.
|
||||
*
|
||||
* Based on arch/x86/include/asm/hugetlb.h
|
||||
*
|
||||
* 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _ASM_ARM_HUGETLB_H
|
||||
#define _ASM_ARM_HUGETLB_H
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <asm-generic/hugetlb.h>
|
||||
|
||||
#include <asm/hugetlb-3level.h>
|
||||
|
||||
static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb,
|
||||
unsigned long addr, unsigned long end,
|
||||
unsigned long floor,
|
||||
unsigned long ceiling)
|
||||
{
|
||||
free_pgd_range(tlb, addr, end, floor, ceiling);
|
||||
}
|
||||
|
||||
|
||||
static inline int is_hugepage_only_range(struct mm_struct *mm,
|
||||
unsigned long addr, unsigned long len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int prepare_hugepage_range(struct file *file,
|
||||
unsigned long addr, unsigned long len)
|
||||
{
|
||||
struct hstate *h = hstate_file(file);
|
||||
if (len & ~huge_page_mask(h))
|
||||
return -EINVAL;
|
||||
if (addr & ~huge_page_mask(h))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int huge_pte_none(pte_t pte)
|
||||
{
|
||||
return pte_none(pte);
|
||||
}
|
||||
|
||||
static inline pte_t huge_pte_wrprotect(pte_t pte)
|
||||
{
|
||||
return pte_wrprotect(pte);
|
||||
}
|
||||
|
||||
static inline int arch_prepare_hugepage(struct page *page)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void arch_release_hugepage(struct page *page)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void arch_clear_hugepage_flags(struct page *page)
|
||||
{
|
||||
clear_bit(PG_dcache_clean, &page->flags);
|
||||
}
|
||||
|
||||
#endif /* _ASM_ARM_HUGETLB_H */
|
||||
|
|
@ -55,8 +55,10 @@
|
|||
* 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
|
||||
|
|
@ -67,8 +69,7 @@
|
|||
*/
|
||||
#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_SWIO | HCR_TIDCP)
|
||||
#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
|
||||
HCR_TVM | HCR_TWE | HCR_SWIO | HCR_TIDCP)
|
||||
|
||||
/* System Control Register (SCTLR) bits */
|
||||
#define SCTLR_TE (1 << 30)
|
||||
|
|
@ -95,12 +96,12 @@
|
|||
#define TTBCR_IRGN1 (3 << 24)
|
||||
#define TTBCR_EPD1 (1 << 23)
|
||||
#define TTBCR_A1 (1 << 22)
|
||||
#define TTBCR_T1SZ (3 << 16)
|
||||
#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 3
|
||||
#define TTBCR_T0SZ (7 << 0)
|
||||
#define HTCR_MASK (TTBCR_T0SZ | TTBCR_IRGN0 | TTBCR_ORGN0 | TTBCR_SH0)
|
||||
|
||||
/* Hyp System Trap Register */
|
||||
|
|
@ -135,7 +136,6 @@
|
|||
#define KVM_PHYS_MASK (KVM_PHYS_SIZE - 1ULL)
|
||||
#define PTRS_PER_S2_PGD (1ULL << (KVM_PHYS_SHIFT - 30))
|
||||
#define S2_PGD_ORDER get_order(PTRS_PER_S2_PGD * sizeof(pgd_t))
|
||||
#define S2_PGD_SIZE (1 << S2_PGD_ORDER)
|
||||
|
||||
/* Virtualization Translation Control Register (VTCR) bits */
|
||||
#define VTCR_SH0 (3 << 12)
|
||||
|
|
@ -209,6 +209,8 @@
|
|||
#define HSR_EC_DABT (0x24)
|
||||
#define HSR_EC_DABT_HYP (0x25)
|
||||
|
||||
#define HSR_WFI_IS_WFE (1U << 0)
|
||||
|
||||
#define HSR_HVC_IMM_MASK ((1UL << 16) - 1)
|
||||
|
||||
#define HSR_DABT_S1PTW (1U << 7)
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
#define c6_IFAR 17 /* Instruction Fault Address Register */
|
||||
#define c7_PAR 18 /* Physical Address Register */
|
||||
#define c7_PAR_high 19 /* PAR top 32 bits */
|
||||
#define c9_L2CTLR 20 /* Cortex A15 L2 Control Register */
|
||||
#define c9_L2CTLR 20 /* Cortex A15/A7 L2 Control Register */
|
||||
#define c10_PRRR 21 /* Primary Region Remap Register */
|
||||
#define c10_NMRR 22 /* Normal Memory Remap Register */
|
||||
#define c12_VBAR 23 /* Vector Base Address Register */
|
||||
|
|
@ -48,7 +48,9 @@
|
|||
#define c13_TID_URO 26 /* Thread ID, User R/O */
|
||||
#define c13_TID_PRIV 27 /* Thread ID, Privileged */
|
||||
#define c14_CNTKCTL 28 /* Timer Control Register (PL1) */
|
||||
#define NR_CP15_REGS 29 /* Number of regs (incl. invalid) */
|
||||
#define c10_AMAIR0 29 /* Auxilary Memory Attribute Indirection Reg0 */
|
||||
#define c10_AMAIR1 30 /* Auxilary Memory Attribute Indirection Reg1 */
|
||||
#define NR_CP15_REGS 31 /* Number of regs (incl. invalid) */
|
||||
|
||||
#define ARM_EXCEPTION_RESET 0
|
||||
#define ARM_EXCEPTION_UNDEFINED 1
|
||||
|
|
@ -59,6 +61,24 @@
|
|||
#define ARM_EXCEPTION_FIQ 6
|
||||
#define ARM_EXCEPTION_HVC 7
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
struct kvm;
|
||||
struct kvm_vcpu;
|
||||
|
|
@ -74,8 +94,6 @@ extern char __kvm_hyp_vector[];
|
|||
extern char __kvm_hyp_code_start[];
|
||||
extern char __kvm_hyp_code_end[];
|
||||
|
||||
extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
|
||||
|
||||
extern void __kvm_flush_vm_context(void);
|
||||
extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
|
||||
|
||||
|
|
|
|||
|
|
@ -65,11 +65,6 @@ static inline bool vcpu_mode_priv(struct kvm_vcpu *vcpu)
|
|||
return cpsr_mode > USR_MODE;;
|
||||
}
|
||||
|
||||
static inline bool kvm_vcpu_reg_is_pc(struct kvm_vcpu *vcpu, int reg)
|
||||
{
|
||||
return reg == 15;
|
||||
}
|
||||
|
||||
static inline u32 kvm_vcpu_get_hsr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return vcpu->arch.fault.hsr;
|
||||
|
|
@ -153,6 +148,11 @@ static inline bool kvm_vcpu_trap_is_iabt(struct kvm_vcpu *vcpu)
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -162,4 +162,69 @@ 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(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return vcpu->arch.cp15[c0_MPIDR];
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __ARM_KVM_EMULATE_H__ */
|
||||
|
|
|
|||
|
|
@ -19,30 +19,31 @@
|
|||
#ifndef __ARM_KVM_HOST_H__
|
||||
#define __ARM_KVM_HOST_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/kvm_types.h>
|
||||
#include <asm/kvm.h>
|
||||
#include <asm/kvm_asm.h>
|
||||
#include <asm/kvm_mmio.h>
|
||||
#include <asm/fpstate.h>
|
||||
#include <asm/kvm_arch_timer.h>
|
||||
#include <kvm/arm_arch_timer.h>
|
||||
|
||||
#if defined(CONFIG_KVM_ARM_MAX_VCPUS)
|
||||
#define KVM_MAX_VCPUS CONFIG_KVM_ARM_MAX_VCPUS
|
||||
#else
|
||||
#define KVM_MAX_VCPUS 0
|
||||
#endif
|
||||
|
||||
#define KVM_USER_MEM_SLOTS 32
|
||||
#define KVM_PRIVATE_MEM_SLOTS 4
|
||||
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
|
||||
#define KVM_HAVE_ONE_REG
|
||||
|
||||
#define KVM_VCPU_MAX_FEATURES 1
|
||||
#define KVM_VCPU_MAX_FEATURES 2
|
||||
|
||||
/* We don't currently support large pages. */
|
||||
#define KVM_HPAGE_GFN_SHIFT(x) 0
|
||||
#define KVM_NR_PAGE_SIZES 1
|
||||
#define KVM_PAGES_PER_HPAGE(x) (1UL<<31)
|
||||
#include <kvm/arm_vgic.h>
|
||||
|
||||
#include <asm/kvm_vgic.h>
|
||||
|
||||
struct kvm_vcpu;
|
||||
u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
|
||||
int kvm_target_cpu(void);
|
||||
int __attribute_const__ kvm_target_cpu(void);
|
||||
int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
|
||||
void kvm_reset_coprocs(struct kvm_vcpu *vcpu);
|
||||
|
||||
|
|
@ -101,6 +102,12 @@ struct kvm_vcpu_arch {
|
|||
/* The CPU type we expose to the VM */
|
||||
u32 midr;
|
||||
|
||||
/* HYP trapping configuration */
|
||||
u32 hcr;
|
||||
|
||||
/* Interrupt related fields */
|
||||
u32 irq_lines; /* IRQ and FIQ levels */
|
||||
|
||||
/* Exception Information */
|
||||
struct kvm_vcpu_fault_info fault;
|
||||
|
||||
|
|
@ -128,9 +135,6 @@ struct kvm_vcpu_arch {
|
|||
/* IO related fields */
|
||||
struct kvm_decode mmio_decode;
|
||||
|
||||
/* Interrupt related fields */
|
||||
u32 irq_lines; /* IRQ and FIQ levels */
|
||||
|
||||
/* Cache some mmu pages needed inside spinlock regions */
|
||||
struct kvm_mmu_memory_cache mmu_page_cache;
|
||||
|
||||
|
|
@ -146,19 +150,17 @@ struct kvm_vcpu_stat {
|
|||
u32 halt_wakeup;
|
||||
};
|
||||
|
||||
struct kvm_vcpu_init;
|
||||
int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
|
||||
const struct kvm_vcpu_init *init);
|
||||
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);
|
||||
struct kvm_one_reg;
|
||||
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);
|
||||
u64 kvm_call_hyp(void *hypfn, ...);
|
||||
void force_vm_exit(const cpumask_t *mask);
|
||||
|
||||
#define KVM_ARCH_WANT_MMU_NOTIFIER
|
||||
struct kvm;
|
||||
int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
|
||||
int kvm_unmap_hva_range(struct kvm *kvm,
|
||||
unsigned long start, unsigned long end);
|
||||
|
|
@ -183,15 +185,14 @@ struct kvm_vcpu __percpu **kvm_get_running_vcpus(void);
|
|||
|
||||
int kvm_arm_copy_coproc_indices(struct kvm_vcpu *vcpu, u64 __user *uindices);
|
||||
unsigned long kvm_arm_num_coproc_regs(struct kvm_vcpu *vcpu);
|
||||
struct kvm_one_reg;
|
||||
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 __cpu_init_hyp_mode(unsigned long long boot_pgd_ptr,
|
||||
unsigned long long pgd_ptr,
|
||||
static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,
|
||||
phys_addr_t pgd_ptr,
|
||||
unsigned long hyp_stack_ptr,
|
||||
unsigned long vector_ptr)
|
||||
{
|
||||
|
|
@ -221,7 +222,18 @@ static inline int kvm_arch_dev_ioctl_check_extension(long ext)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void vgic_arch_setup(const struct vgic_params *vgic)
|
||||
{
|
||||
BUG_ON(vgic->type != VGIC_V2);
|
||||
}
|
||||
|
||||
int kvm_perf_init(void);
|
||||
int kvm_perf_teardown(void);
|
||||
|
||||
static inline void kvm_arch_hardware_disable(void) {}
|
||||
static inline void kvm_arch_hardware_unsetup(void) {}
|
||||
static inline void kvm_arch_sync_events(struct kvm *kvm) {}
|
||||
static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {}
|
||||
static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
|
||||
|
||||
#endif /* __ARM_KVM_HOST_H__ */
|
||||
|
|
|
|||
|
|
@ -62,9 +62,15 @@ phys_addr_t kvm_get_idmap_vector(void);
|
|||
int kvm_mmu_init(void);
|
||||
void kvm_clear_hyp_idmap(void);
|
||||
|
||||
static inline void kvm_set_pmd(pmd_t *pmd, pmd_t new_pmd)
|
||||
{
|
||||
*pmd = new_pmd;
|
||||
flush_pmd_entry(pmd);
|
||||
}
|
||||
|
||||
static inline void kvm_set_pte(pte_t *pte, pte_t new_pte)
|
||||
{
|
||||
pte_val(*pte) = new_pte;
|
||||
*pte = new_pte;
|
||||
/*
|
||||
* flush_pmd_entry just takes a void pointer and cleans the necessary
|
||||
* cache entries, so we can reuse the function for ptes.
|
||||
|
|
@ -72,17 +78,6 @@ static inline void kvm_set_pte(pte_t *pte, pte_t new_pte)
|
|||
flush_pmd_entry(pte);
|
||||
}
|
||||
|
||||
static inline bool kvm_is_write_fault(unsigned long hsr)
|
||||
{
|
||||
unsigned long hsr_ec = hsr >> HSR_EC_SHIFT;
|
||||
if (hsr_ec == HSR_EC_IABT)
|
||||
return false;
|
||||
else if ((hsr & HSR_ISV) && !(hsr & HSR_WNR))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void kvm_clean_pgd(pgd_t *pgd)
|
||||
{
|
||||
clean_dcache_area(pgd, PTRS_PER_S2_PGD * sizeof(pgd_t));
|
||||
|
|
@ -103,10 +98,51 @@ static inline void kvm_set_s2pte_writable(pte_t *pte)
|
|||
pte_val(*pte) |= L_PTE_S2_RDWR;
|
||||
}
|
||||
|
||||
static inline void kvm_set_s2pmd_writable(pmd_t *pmd)
|
||||
{
|
||||
pmd_val(*pmd) |= L_PMD_S2_RDWR;
|
||||
}
|
||||
|
||||
/* Open coded p*d_addr_end that can deal with 64bit addresses */
|
||||
#define kvm_pgd_addr_end(addr, end) \
|
||||
({ u64 __boundary = ((addr) + PGDIR_SIZE) & PGDIR_MASK; \
|
||||
(__boundary - 1 < (end) - 1)? __boundary: (end); \
|
||||
})
|
||||
|
||||
#define kvm_pud_addr_end(addr,end) (end)
|
||||
|
||||
#define kvm_pmd_addr_end(addr, end) \
|
||||
({ u64 __boundary = ((addr) + PMD_SIZE) & PMD_MASK; \
|
||||
(__boundary - 1 < (end) - 1)? __boundary: (end); \
|
||||
})
|
||||
|
||||
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(ptep) kvm_page_empty(ptep)
|
||||
#define kvm_pmd_table_empty(pmdp) kvm_page_empty(pmdp)
|
||||
#define kvm_pud_table_empty(pudp) (0)
|
||||
|
||||
|
||||
struct kvm;
|
||||
|
||||
static inline void coherent_icache_guest_page(struct kvm *kvm, gfn_t gfn)
|
||||
#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->arch.cp15[c1_SCTLR] & 0b101) == 0b101;
|
||||
}
|
||||
|
||||
static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva,
|
||||
unsigned long size)
|
||||
{
|
||||
if (!vcpu_has_cache_enabled(vcpu))
|
||||
kvm_flush_dcache_to_poc((void *)hva, size);
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
|
@ -120,15 +156,16 @@ static inline void coherent_icache_guest_page(struct kvm *kvm, gfn_t gfn)
|
|||
* need any kind of flushing (DDI 0406C.b - Page B3-1392).
|
||||
*/
|
||||
if (icache_is_pipt()) {
|
||||
unsigned long hva = gfn_to_hva(kvm, gfn);
|
||||
__cpuc_coherent_user_range(hva, hva + PAGE_SIZE);
|
||||
__cpuc_coherent_user_range(hva, hva + size);
|
||||
} else if (!icache_is_vivt_asid_tagged()) {
|
||||
/* any kind of VIPT cache */
|
||||
__flush_icache_all();
|
||||
}
|
||||
}
|
||||
|
||||
#define kvm_flush_dcache_to_poc(a,l) __cpuc_flush_dcache_area((a), (l))
|
||||
#define kvm_virt_to_phys(x) virt_to_idmap((unsigned long)(x))
|
||||
|
||||
void stage2_flush_vm(struct kvm *kvm);
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@
|
|||
#ifndef __ARM_KVM_PSCI_H__
|
||||
#define __ARM_KVM_PSCI_H__
|
||||
|
||||
bool kvm_psci_call(struct kvm_vcpu *vcpu);
|
||||
#define KVM_ARM_PSCI_0_1 1
|
||||
#define KVM_ARM_PSCI_0_2 2
|
||||
|
||||
int kvm_psci_version(struct kvm_vcpu *vcpu);
|
||||
int kvm_psci_call(struct kvm_vcpu *vcpu);
|
||||
|
||||
#endif /* __ARM_KVM_PSCI_H__ */
|
||||
|
|
|
|||
|
|
@ -1,220 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012 ARM Ltd.
|
||||
* Author: Marc Zyngier <marc.zyngier@arm.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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __ASM_ARM_KVM_VGIC_H
|
||||
#define __ASM_ARM_KVM_VGIC_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kvm.h>
|
||||
#include <linux/irqreturn.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/irqchip/arm-gic.h>
|
||||
|
||||
#define VGIC_NR_IRQS 128
|
||||
#define VGIC_NR_SGIS 16
|
||||
#define VGIC_NR_PPIS 16
|
||||
#define VGIC_NR_PRIVATE_IRQS (VGIC_NR_SGIS + VGIC_NR_PPIS)
|
||||
#define VGIC_NR_SHARED_IRQS (VGIC_NR_IRQS - VGIC_NR_PRIVATE_IRQS)
|
||||
#define VGIC_MAX_CPUS KVM_MAX_VCPUS
|
||||
#define VGIC_MAX_LRS (1 << 6)
|
||||
|
||||
/* Sanity checks... */
|
||||
#if (VGIC_MAX_CPUS > 8)
|
||||
#error Invalid number of CPU interfaces
|
||||
#endif
|
||||
|
||||
#if (VGIC_NR_IRQS & 31)
|
||||
#error "VGIC_NR_IRQS must be a multiple of 32"
|
||||
#endif
|
||||
|
||||
#if (VGIC_NR_IRQS > 1024)
|
||||
#error "VGIC_NR_IRQS must be <= 1024"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The GIC distributor registers describing interrupts have two parts:
|
||||
* - 32 per-CPU interrupts (SGI + PPI)
|
||||
* - a bunch of shared interrupts (SPI)
|
||||
*/
|
||||
struct vgic_bitmap {
|
||||
union {
|
||||
u32 reg[VGIC_NR_PRIVATE_IRQS / 32];
|
||||
DECLARE_BITMAP(reg_ul, VGIC_NR_PRIVATE_IRQS);
|
||||
} percpu[VGIC_MAX_CPUS];
|
||||
union {
|
||||
u32 reg[VGIC_NR_SHARED_IRQS / 32];
|
||||
DECLARE_BITMAP(reg_ul, VGIC_NR_SHARED_IRQS);
|
||||
} shared;
|
||||
};
|
||||
|
||||
struct vgic_bytemap {
|
||||
u32 percpu[VGIC_MAX_CPUS][VGIC_NR_PRIVATE_IRQS / 4];
|
||||
u32 shared[VGIC_NR_SHARED_IRQS / 4];
|
||||
};
|
||||
|
||||
struct vgic_dist {
|
||||
#ifdef CONFIG_KVM_ARM_VGIC
|
||||
spinlock_t lock;
|
||||
bool ready;
|
||||
|
||||
/* Virtual control interface mapping */
|
||||
void __iomem *vctrl_base;
|
||||
|
||||
/* Distributor and vcpu interface mapping in the guest */
|
||||
phys_addr_t vgic_dist_base;
|
||||
phys_addr_t vgic_cpu_base;
|
||||
|
||||
/* Distributor enabled */
|
||||
u32 enabled;
|
||||
|
||||
/* Interrupt enabled (one bit per IRQ) */
|
||||
struct vgic_bitmap irq_enabled;
|
||||
|
||||
/* Interrupt 'pin' level */
|
||||
struct vgic_bitmap irq_state;
|
||||
|
||||
/* Level-triggered interrupt in progress */
|
||||
struct vgic_bitmap irq_active;
|
||||
|
||||
/* Interrupt priority. Not used yet. */
|
||||
struct vgic_bytemap irq_priority;
|
||||
|
||||
/* Level/edge triggered */
|
||||
struct vgic_bitmap irq_cfg;
|
||||
|
||||
/* Source CPU per SGI and target CPU */
|
||||
u8 irq_sgi_sources[VGIC_MAX_CPUS][VGIC_NR_SGIS];
|
||||
|
||||
/* Target CPU for each IRQ */
|
||||
u8 irq_spi_cpu[VGIC_NR_SHARED_IRQS];
|
||||
struct vgic_bitmap irq_spi_target[VGIC_MAX_CPUS];
|
||||
|
||||
/* Bitmap indicating which CPU has something pending */
|
||||
unsigned long irq_pending_on_cpu;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct vgic_cpu {
|
||||
#ifdef CONFIG_KVM_ARM_VGIC
|
||||
/* per IRQ to LR mapping */
|
||||
u8 vgic_irq_lr_map[VGIC_NR_IRQS];
|
||||
|
||||
/* Pending interrupts on this VCPU */
|
||||
DECLARE_BITMAP( pending_percpu, VGIC_NR_PRIVATE_IRQS);
|
||||
DECLARE_BITMAP( pending_shared, VGIC_NR_SHARED_IRQS);
|
||||
|
||||
/* Bitmap of used/free list registers */
|
||||
DECLARE_BITMAP( lr_used, VGIC_MAX_LRS);
|
||||
|
||||
/* Number of list registers on this CPU */
|
||||
int nr_lr;
|
||||
|
||||
/* CPU vif control registers for world switch */
|
||||
u32 vgic_hcr;
|
||||
u32 vgic_vmcr;
|
||||
u32 vgic_misr; /* Saved only */
|
||||
u32 vgic_eisr[2]; /* Saved only */
|
||||
u32 vgic_elrsr[2]; /* Saved only */
|
||||
u32 vgic_apr;
|
||||
u32 vgic_lr[VGIC_MAX_LRS];
|
||||
#endif
|
||||
};
|
||||
|
||||
#define LR_EMPTY 0xff
|
||||
|
||||
struct kvm;
|
||||
struct kvm_vcpu;
|
||||
struct kvm_run;
|
||||
struct kvm_exit_mmio;
|
||||
|
||||
#ifdef CONFIG_KVM_ARM_VGIC
|
||||
int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr);
|
||||
int kvm_vgic_hyp_init(void);
|
||||
int kvm_vgic_init(struct kvm *kvm);
|
||||
int kvm_vgic_create(struct kvm *kvm);
|
||||
int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu);
|
||||
void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
|
||||
void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
|
||||
int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
|
||||
bool level);
|
||||
int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
|
||||
bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
||||
struct kvm_exit_mmio *mmio);
|
||||
|
||||
#define irqchip_in_kernel(k) (!!((k)->arch.vgic.vctrl_base))
|
||||
#define vgic_initialized(k) ((k)->arch.vgic.ready)
|
||||
|
||||
#else
|
||||
static inline int kvm_vgic_hyp_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int kvm_vgic_init(struct kvm *kvm)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int kvm_vgic_create(struct kvm *kvm)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu) {}
|
||||
static inline void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu) {}
|
||||
|
||||
static inline int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid,
|
||||
unsigned int irq_num, bool level)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
||||
struct kvm_exit_mmio *mmio)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int irqchip_in_kernel(struct kvm *kvm)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool vgic_initialized(struct kvm *kvm)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -157,6 +157,7 @@
|
|||
*/
|
||||
#define __PV_BITS_31_24 0x81000000
|
||||
|
||||
extern phys_addr_t (*arch_virt_to_idmap) (unsigned long x);
|
||||
extern unsigned long __pv_phys_offset;
|
||||
#define PHYS_OFFSET __pv_phys_offset
|
||||
|
||||
|
|
@ -232,6 +233,21 @@ static inline void *phys_to_virt(phys_addr_t x)
|
|||
#define __va(x) ((void *)__phys_to_virt((unsigned long)(x)))
|
||||
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
|
||||
|
||||
/*
|
||||
* These are for systems that have a hardware interconnect supported alias of
|
||||
* physical memory for idmap purposes. Most cases should leave these
|
||||
* untouched.
|
||||
*/
|
||||
static inline phys_addr_t __virt_to_idmap(unsigned long x)
|
||||
{
|
||||
if (arch_virt_to_idmap)
|
||||
return arch_virt_to_idmap(x);
|
||||
else
|
||||
return __virt_to_phys(x);
|
||||
}
|
||||
|
||||
#define virt_to_idmap(x) __virt_to_idmap((unsigned long)(x))
|
||||
|
||||
/*
|
||||
* Virtual <-> DMA view memory address translations
|
||||
* Again, these are *only* valid on the kernel direct mapped RAM
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#define PMD_TYPE_FAULT (_AT(pmdval_t, 0) << 0)
|
||||
#define PMD_TYPE_TABLE (_AT(pmdval_t, 3) << 0)
|
||||
#define PMD_TYPE_SECT (_AT(pmdval_t, 1) << 0)
|
||||
#define PMD_TABLE_BIT (_AT(pmdval_t, 1) << 1)
|
||||
#define PMD_BIT4 (_AT(pmdval_t, 0))
|
||||
#define PMD_DOMAIN(x) (_AT(pmdval_t, 0))
|
||||
#define PMD_APTABLE_SHIFT (61)
|
||||
|
|
@ -41,6 +42,8 @@
|
|||
*/
|
||||
#define PMD_SECT_BUFFERABLE (_AT(pmdval_t, 1) << 2)
|
||||
#define PMD_SECT_CACHEABLE (_AT(pmdval_t, 1) << 3)
|
||||
#define PMD_SECT_USER (_AT(pmdval_t, 1) << 6) /* AP[1] */
|
||||
#define PMD_SECT_RDONLY (_AT(pmdval_t, 1) << 7) /* AP[2] */
|
||||
#define PMD_SECT_S (_AT(pmdval_t, 3) << 8)
|
||||
#define PMD_SECT_AF (_AT(pmdval_t, 1) << 10)
|
||||
#define PMD_SECT_nG (_AT(pmdval_t, 1) << 11)
|
||||
|
|
@ -66,6 +69,7 @@
|
|||
#define PTE_TYPE_MASK (_AT(pteval_t, 3) << 0)
|
||||
#define PTE_TYPE_FAULT (_AT(pteval_t, 0) << 0)
|
||||
#define PTE_TYPE_PAGE (_AT(pteval_t, 3) << 0)
|
||||
#define PTE_TABLE_BIT (_AT(pteval_t, 1) << 1)
|
||||
#define PTE_BUFFERABLE (_AT(pteval_t, 1) << 2) /* AttrIndx[0] */
|
||||
#define PTE_CACHEABLE (_AT(pteval_t, 1) << 3) /* AttrIndx[1] */
|
||||
#define PTE_EXT_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */
|
||||
|
|
|
|||
|
|
@ -61,6 +61,14 @@
|
|||
|
||||
#define USER_PTRS_PER_PGD (PAGE_OFFSET / PGDIR_SIZE)
|
||||
|
||||
/*
|
||||
* Hugetlb definitions.
|
||||
*/
|
||||
#define HPAGE_SHIFT PMD_SHIFT
|
||||
#define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT)
|
||||
#define HPAGE_MASK (~(HPAGE_SIZE - 1))
|
||||
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
|
||||
|
||||
/*
|
||||
* "Linux" PTE definitions for LPAE.
|
||||
*
|
||||
|
|
@ -79,6 +87,11 @@
|
|||
#define L_PTE_SPECIAL (_AT(pteval_t, 1) << 56) /* unused */
|
||||
#define L_PTE_NONE (_AT(pteval_t, 1) << 57) /* PROT_NONE */
|
||||
|
||||
#define PMD_SECT_VALID (_AT(pmdval_t, 1) << 0)
|
||||
#define PMD_SECT_DIRTY (_AT(pmdval_t, 1) << 55)
|
||||
#define PMD_SECT_SPLITTING (_AT(pmdval_t, 1) << 56)
|
||||
#define PMD_SECT_NONE (_AT(pmdval_t, 1) << 57)
|
||||
|
||||
/*
|
||||
* To be used in assembly code with the upper page attributes.
|
||||
*/
|
||||
|
|
@ -113,6 +126,8 @@
|
|||
#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_RDWR (_AT(pmdval_t, 3) << 6) /* HAP[2:1] */
|
||||
|
||||
/*
|
||||
* Hyp-mode PL2 PTE definitions for LPAE.
|
||||
*/
|
||||
|
|
@ -166,8 +181,83 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
|
|||
clean_pmd_entry(pmdp); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* For 3 levels of paging the PTE_EXT_NG bit will be set for user address ptes
|
||||
* that are written to a page table but not for ptes created with mk_pte.
|
||||
*
|
||||
* In hugetlb_no_page, a new huge pte (new_pte) is generated and passed to
|
||||
* hugetlb_cow, where it is compared with an entry in a page table.
|
||||
* This comparison test fails erroneously leading ultimately to a memory leak.
|
||||
*
|
||||
* To correct this behaviour, we mask off PTE_EXT_NG for any pte that is
|
||||
* present before running the comparison.
|
||||
*/
|
||||
#define __HAVE_ARCH_PTE_SAME
|
||||
#define pte_same(pte_a,pte_b) ((pte_present(pte_a) ? pte_val(pte_a) & ~PTE_EXT_NG \
|
||||
: pte_val(pte_a)) \
|
||||
== (pte_present(pte_b) ? pte_val(pte_b) & ~PTE_EXT_NG \
|
||||
: pte_val(pte_b)))
|
||||
|
||||
#define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,__pte(pte_val(pte)|(ext)))
|
||||
|
||||
#define pte_huge(pte) (pte_val(pte) && !(pte_val(pte) & PTE_TABLE_BIT))
|
||||
#define pte_mkhuge(pte) (__pte(pte_val(pte) & ~PTE_TABLE_BIT))
|
||||
|
||||
#define pmd_young(pmd) (pmd_val(pmd) & PMD_SECT_AF)
|
||||
|
||||
#define __HAVE_ARCH_PMD_WRITE
|
||||
#define pmd_write(pmd) (!(pmd_val(pmd) & PMD_SECT_RDONLY))
|
||||
|
||||
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
#define pmd_trans_huge(pmd) (pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT))
|
||||
#define pmd_trans_splitting(pmd) (pmd_val(pmd) & PMD_SECT_SPLITTING)
|
||||
#endif
|
||||
|
||||
#define PMD_BIT_FUNC(fn,op) \
|
||||
static inline pmd_t pmd_##fn(pmd_t pmd) { pmd_val(pmd) op; return pmd; }
|
||||
|
||||
PMD_BIT_FUNC(wrprotect, |= PMD_SECT_RDONLY);
|
||||
PMD_BIT_FUNC(mkold, &= ~PMD_SECT_AF);
|
||||
PMD_BIT_FUNC(mksplitting, |= PMD_SECT_SPLITTING);
|
||||
PMD_BIT_FUNC(mkwrite, &= ~PMD_SECT_RDONLY);
|
||||
PMD_BIT_FUNC(mkdirty, |= PMD_SECT_DIRTY);
|
||||
PMD_BIT_FUNC(mkyoung, |= PMD_SECT_AF);
|
||||
|
||||
#define pmd_mkhuge(pmd) (__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
|
||||
|
||||
#define pmd_pfn(pmd) (((pmd_val(pmd) & PMD_MASK) & PHYS_MASK) >> PAGE_SHIFT)
|
||||
#define pfn_pmd(pfn,prot) (__pmd(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))
|
||||
#define mk_pmd(page,prot) pfn_pmd(page_to_pfn(page),prot)
|
||||
|
||||
/* represent a notpresent pmd by zero, this is used by pmdp_invalidate */
|
||||
#define pmd_mknotpresent(pmd) (__pmd(0))
|
||||
|
||||
static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
|
||||
{
|
||||
const pmdval_t mask = PMD_SECT_USER | PMD_SECT_XN | PMD_SECT_RDONLY |
|
||||
PMD_SECT_VALID | PMD_SECT_NONE;
|
||||
pmd_val(pmd) = (pmd_val(pmd) & ~mask) | (pgprot_val(newprot) & mask);
|
||||
return pmd;
|
||||
}
|
||||
|
||||
static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
|
||||
pmd_t *pmdp, pmd_t pmd)
|
||||
{
|
||||
BUG_ON(addr >= TASK_SIZE);
|
||||
|
||||
/* create a faulting entry if PROT_NONE protected */
|
||||
if (pmd_val(pmd) & PMD_SECT_NONE)
|
||||
pmd_val(pmd) &= ~PMD_SECT_VALID;
|
||||
|
||||
*pmdp = __pmd(pmd_val(pmd) | PMD_SECT_nG);
|
||||
flush_pmd_entry(pmdp);
|
||||
}
|
||||
|
||||
static inline int has_transparent_hugepage(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* _ASM_PGTABLE_3LEVEL_H */
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@
|
|||
#include <asm/memory.h>
|
||||
#include <asm/pgtable-hwdef.h>
|
||||
|
||||
|
||||
#include <asm/tlbflush.h>
|
||||
|
||||
#ifdef CONFIG_ARM_LPAE
|
||||
#include <asm/pgtable-3level.h>
|
||||
#else
|
||||
|
|
@ -97,7 +100,7 @@ extern pgprot_t pgprot_s2_device;
|
|||
#define PAGE_HYP _MOD_PROT(pgprot_kernel, L_PTE_HYP)
|
||||
#define PAGE_HYP_DEVICE _MOD_PROT(pgprot_hyp_device, L_PTE_HYP)
|
||||
#define PAGE_S2 _MOD_PROT(pgprot_s2, L_PTE_S2_RDONLY)
|
||||
#define PAGE_S2_DEVICE _MOD_PROT(pgprot_s2_device, L_PTE_USER | L_PTE_S2_RDONLY)
|
||||
#define PAGE_S2_DEVICE _MOD_PROT(pgprot_s2_device, L_PTE_S2_RDWR)
|
||||
|
||||
#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)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
static inline bool scu_a9_has_base(void)
|
||||
{
|
||||
return read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A9;
|
||||
return read_cpuid_part() == ARM_CPU_PART_CORTEX_A9;
|
||||
}
|
||||
|
||||
static inline unsigned long scu_a9_get_base(void)
|
||||
|
|
|
|||
|
|
@ -103,8 +103,7 @@ static inline void syscall_set_arguments(struct task_struct *task,
|
|||
memcpy(®s->ARM_r0 + i, args, n * sizeof(args[0]));
|
||||
}
|
||||
|
||||
static inline int syscall_get_arch(struct task_struct *task,
|
||||
struct pt_regs *regs)
|
||||
static inline int syscall_get_arch(void)
|
||||
{
|
||||
/* ARM tasks don't change audit architectures on the fly. */
|
||||
return AUDIT_ARCH_ARM;
|
||||
|
|
|
|||
|
|
@ -207,6 +207,12 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
tlb_remove_pmd_tlb_entry(struct mmu_gather *tlb, pmd_t *pmdp, unsigned long addr)
|
||||
{
|
||||
tlb_add_flush(tlb, addr);
|
||||
}
|
||||
|
||||
#define pte_free_tlb(tlb, ptep, addr) __pte_free_tlb(tlb, ptep, addr)
|
||||
#define pmd_free_tlb(tlb, pmdp, addr) __pmd_free_tlb(tlb, pmdp, addr)
|
||||
#define pud_free_tlb(tlb, pudp, addr) pud_free((tlb)->mm, pudp)
|
||||
|
|
|
|||
|
|
@ -535,6 +535,8 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
|
|||
}
|
||||
#endif
|
||||
|
||||
#define update_mmu_cache_pmd(vma, address, pmd) do { } while (0)
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_MMU */
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include <uapi/asm/unistd.h>
|
||||
|
||||
#define __NR_syscalls (380)
|
||||
#define __NR_syscalls (384)
|
||||
#define __ARM_NR_cmpxchg (__ARM_NR_BASE+0x00fff0)
|
||||
|
||||
#define __ARCH_WANT_STAT64
|
||||
|
|
|
|||
|
|
@ -20,10 +20,12 @@
|
|||
#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_REG_SIZE(id) \
|
||||
(1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
|
||||
|
|
@ -63,7 +65,8 @@ struct kvm_regs {
|
|||
|
||||
/* Supported Processor Types */
|
||||
#define KVM_ARM_TARGET_CORTEX_A15 0
|
||||
#define KVM_ARM_NUM_TARGETS 1
|
||||
#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
|
||||
|
|
@ -82,6 +85,7 @@ struct kvm_regs {
|
|||
#define KVM_VGIC_V2_CPU_SIZE 0x2000
|
||||
|
||||
#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;
|
||||
|
|
@ -118,6 +122,26 @@ struct kvm_arch_memory_slot {
|
|||
#define KVM_REG_ARM_32_CRN_MASK 0x0000000000007800
|
||||
#define KVM_REG_ARM_32_CRN_SHIFT 11
|
||||
|
||||
#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__)
|
||||
|
||||
#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)
|
||||
|
|
@ -142,6 +166,15 @@ struct kvm_arch_memory_slot {
|
|||
#define KVM_REG_ARM_VFP_FPINST 0x1009
|
||||
#define KVM_REG_ARM_VFP_FPINST2 0x100A
|
||||
|
||||
/* 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_OFFSET_SHIFT 0
|
||||
#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
|
||||
#define KVM_DEV_ARM_VGIC_GRP_NR_IRQS 3
|
||||
|
||||
/* KVM_IRQ_LINE irq field index values */
|
||||
#define KVM_ARM_IRQ_TYPE_SHIFT 24
|
||||
|
|
@ -172,9 +205,9 @@ struct kvm_arch_memory_slot {
|
|||
#define KVM_PSCI_FN_CPU_ON KVM_PSCI_FN(2)
|
||||
#define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3)
|
||||
|
||||
#define KVM_PSCI_RET_SUCCESS 0
|
||||
#define KVM_PSCI_RET_NI ((unsigned long)-1)
|
||||
#define KVM_PSCI_RET_INVAL ((unsigned long)-2)
|
||||
#define KVM_PSCI_RET_DENIED ((unsigned long)-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__ */
|
||||
|
|
|
|||
|
|
@ -406,6 +406,12 @@
|
|||
#define __NR_process_vm_writev (__NR_SYSCALL_BASE+377)
|
||||
#define __NR_kcmp (__NR_SYSCALL_BASE+378)
|
||||
#define __NR_finit_module (__NR_SYSCALL_BASE+379)
|
||||
/* Reserve for later
|
||||
#define __NR_sched_setattr (__NR_SYSCALL_BASE+380)
|
||||
#define __NR_sched_getattr (__NR_SYSCALL_BASE+381)
|
||||
#define __NR_renameat2 (__NR_SYSCALL_BASE+382)
|
||||
*/
|
||||
#define __NR_seccomp (__NR_SYSCALL_BASE+383)
|
||||
|
||||
/*
|
||||
* This may need to be greater than __NR_last_syscall+1 in order to
|
||||
|
|
|
|||
|
|
@ -168,6 +168,7 @@ int main(void)
|
|||
DEFINE(VCPU_FIQ_REGS, offsetof(struct kvm_vcpu, arch.regs.fiq_regs));
|
||||
DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.regs.usr_regs.ARM_pc));
|
||||
DEFINE(VCPU_CPSR, offsetof(struct kvm_vcpu, arch.regs.usr_regs.ARM_cpsr));
|
||||
DEFINE(VCPU_HCR, offsetof(struct kvm_vcpu, arch.hcr));
|
||||
DEFINE(VCPU_IRQ_LINES, offsetof(struct kvm_vcpu, arch.irq_lines));
|
||||
DEFINE(VCPU_HSR, offsetof(struct kvm_vcpu, arch.fault.hsr));
|
||||
DEFINE(VCPU_HxFAR, offsetof(struct kvm_vcpu, arch.fault.hxfar));
|
||||
|
|
@ -175,13 +176,13 @@ int main(void)
|
|||
DEFINE(VCPU_HYP_PC, offsetof(struct kvm_vcpu, arch.fault.hyp_pc));
|
||||
#ifdef CONFIG_KVM_ARM_VGIC
|
||||
DEFINE(VCPU_VGIC_CPU, offsetof(struct kvm_vcpu, arch.vgic_cpu));
|
||||
DEFINE(VGIC_CPU_HCR, offsetof(struct vgic_cpu, vgic_hcr));
|
||||
DEFINE(VGIC_CPU_VMCR, offsetof(struct vgic_cpu, vgic_vmcr));
|
||||
DEFINE(VGIC_CPU_MISR, offsetof(struct vgic_cpu, vgic_misr));
|
||||
DEFINE(VGIC_CPU_EISR, offsetof(struct vgic_cpu, vgic_eisr));
|
||||
DEFINE(VGIC_CPU_ELRSR, offsetof(struct vgic_cpu, vgic_elrsr));
|
||||
DEFINE(VGIC_CPU_APR, offsetof(struct vgic_cpu, vgic_apr));
|
||||
DEFINE(VGIC_CPU_LR, offsetof(struct vgic_cpu, vgic_lr));
|
||||
DEFINE(VGIC_V2_CPU_HCR, offsetof(struct vgic_cpu, vgic_v2.vgic_hcr));
|
||||
DEFINE(VGIC_V2_CPU_VMCR, offsetof(struct vgic_cpu, vgic_v2.vgic_vmcr));
|
||||
DEFINE(VGIC_V2_CPU_MISR, offsetof(struct vgic_cpu, vgic_v2.vgic_misr));
|
||||
DEFINE(VGIC_V2_CPU_EISR, offsetof(struct vgic_cpu, vgic_v2.vgic_eisr));
|
||||
DEFINE(VGIC_V2_CPU_ELRSR, offsetof(struct vgic_cpu, vgic_v2.vgic_elrsr));
|
||||
DEFINE(VGIC_V2_CPU_APR, offsetof(struct vgic_cpu, vgic_v2.vgic_apr));
|
||||
DEFINE(VGIC_V2_CPU_LR, offsetof(struct vgic_cpu, vgic_v2.vgic_lr));
|
||||
DEFINE(VGIC_CPU_NR_LR, offsetof(struct vgic_cpu, nr_lr));
|
||||
#ifdef CONFIG_KVM_ARM_TIMER
|
||||
DEFINE(VCPU_TIMER_CNTV_CTL, offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_ctl));
|
||||
|
|
|
|||
|
|
@ -389,6 +389,11 @@
|
|||
CALL(sys_process_vm_writev)
|
||||
CALL(sys_kcmp)
|
||||
CALL(sys_finit_module)
|
||||
/* 380 */ CALL(sys_ni_syscall) /* reserved sys_sched_setattr */
|
||||
CALL(sys_ni_syscall) /* reserved sys_sched_getattr */
|
||||
CALL(sys_ni_syscall) /* reserved sys_renameat2 */
|
||||
CALL(sys_seccomp)
|
||||
|
||||
#ifndef syscalls_counted
|
||||
.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
|
||||
#define syscalls_counted
|
||||
|
|
|
|||
|
|
@ -362,6 +362,16 @@ ENTRY(vector_swi)
|
|||
str r0, [sp, #S_OLD_R0] @ Save OLD_R0
|
||||
zero_fp
|
||||
|
||||
#ifdef CONFIG_ALIGNMENT_TRAP
|
||||
ldr ip, __cr_alignment
|
||||
ldr ip, [ip]
|
||||
mcr p15, 0, ip, c1, c0 @ update control register
|
||||
#endif
|
||||
|
||||
enable_irq
|
||||
ct_user_exit
|
||||
get_thread_info tsk
|
||||
|
||||
/*
|
||||
* Get the system call number.
|
||||
*/
|
||||
|
|
@ -375,9 +385,9 @@ ENTRY(vector_swi)
|
|||
#ifdef CONFIG_ARM_THUMB
|
||||
tst r8, #PSR_T_BIT
|
||||
movne r10, #0 @ no thumb OABI emulation
|
||||
ldreq r10, [lr, #-4] @ get SWI instruction
|
||||
USER( ldreq r10, [lr, #-4] ) @ get SWI instruction
|
||||
#else
|
||||
ldr r10, [lr, #-4] @ get SWI instruction
|
||||
USER( ldr r10, [lr, #-4] ) @ get SWI instruction
|
||||
#endif
|
||||
ARM_BE8(rev r10, r10) @ little endian instruction
|
||||
|
||||
|
|
@ -390,22 +400,13 @@ ENTRY(vector_swi)
|
|||
/* Legacy ABI only, possibly thumb mode. */
|
||||
tst r8, #PSR_T_BIT @ this is SPSR from save_user_regs
|
||||
addne scno, r7, #__NR_SYSCALL_BASE @ put OS number in
|
||||
ldreq scno, [lr, #-4]
|
||||
USER( ldreq scno, [lr, #-4] )
|
||||
|
||||
#else
|
||||
/* Legacy ABI only. */
|
||||
ldr scno, [lr, #-4] @ get SWI instruction
|
||||
USER( ldr scno, [lr, #-4] ) @ get SWI instruction
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ALIGNMENT_TRAP
|
||||
ldr ip, __cr_alignment
|
||||
ldr ip, [ip]
|
||||
mcr p15, 0, ip, c1, c0 @ update control register
|
||||
#endif
|
||||
enable_irq
|
||||
ct_user_exit
|
||||
|
||||
get_thread_info tsk
|
||||
adr tbl, sys_call_table @ load syscall table pointer
|
||||
|
||||
#if defined(CONFIG_OABI_COMPAT)
|
||||
|
|
@ -440,6 +441,21 @@ local_restart:
|
|||
eor r0, scno, #__NR_SYSCALL_BASE @ put OS number back
|
||||
bcs arm_syscall
|
||||
b sys_ni_syscall @ not private func
|
||||
|
||||
#if defined(CONFIG_OABI_COMPAT) || !defined(CONFIG_AEABI)
|
||||
/*
|
||||
* We failed to handle a fault trying to access the page
|
||||
* containing the swi instruction, but we're not really in a
|
||||
* position to return -EFAULT. Instead, return back to the
|
||||
* instruction and re-enter the user fault handling path trying
|
||||
* to page it in. This will likely result in sending SEGV to the
|
||||
* current task.
|
||||
*/
|
||||
9001:
|
||||
sub lr, lr, #4
|
||||
str lr, [sp, #S_PC]
|
||||
b ret_fast_syscall
|
||||
#endif
|
||||
ENDPROC(vector_swi)
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ static bool migrate_one_irq(struct irq_desc *desc)
|
|||
c = irq_data_get_irq_chip(d);
|
||||
if (!c->irq_set_affinity)
|
||||
pr_debug("IRQ%u: unable to set affinity\n", d->irq);
|
||||
else if (c->irq_set_affinity(d, affinity, true) == IRQ_SET_MASK_OK && ret)
|
||||
else if (c->irq_set_affinity(d, affinity, false) == IRQ_SET_MASK_OK && ret)
|
||||
cpumask_copy(d->affinity, affinity);
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <asm/system_info.h>
|
||||
#include <asm/opcodes.h>
|
||||
|
||||
#include "kprobes.h"
|
||||
|
||||
|
|
@ -305,7 +306,8 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi)
|
|||
|
||||
if (handler) {
|
||||
/* We can emulate the instruction in (possibly) modified form */
|
||||
asi->insn[0] = (insn & 0xfff00000) | (rn << 16) | reglist;
|
||||
asi->insn[0] = __opcode_to_mem_arm((insn & 0xfff00000) |
|
||||
(rn << 16) | reglist);
|
||||
asi->insn_handler = handler;
|
||||
return INSN_GOOD;
|
||||
}
|
||||
|
|
@ -334,13 +336,14 @@ prepare_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
|
|||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
if (thumb) {
|
||||
u16 *thumb_insn = (u16 *)asi->insn;
|
||||
thumb_insn[1] = 0x4770; /* Thumb bx lr */
|
||||
thumb_insn[2] = 0x4770; /* Thumb bx lr */
|
||||
/* Thumb bx lr */
|
||||
thumb_insn[1] = __opcode_to_mem_thumb16(0x4770);
|
||||
thumb_insn[2] = __opcode_to_mem_thumb16(0x4770);
|
||||
return insn;
|
||||
}
|
||||
asi->insn[1] = 0xe12fff1e; /* ARM bx lr */
|
||||
asi->insn[1] = __opcode_to_mem_arm(0xe12fff1e); /* ARM bx lr */
|
||||
#else
|
||||
asi->insn[1] = 0xe1a0f00e; /* mov pc, lr */
|
||||
asi->insn[1] = __opcode_to_mem_arm(0xe1a0f00e); /* mov pc, lr */
|
||||
#endif
|
||||
/* Make an ARM instruction unconditional */
|
||||
if (insn < 0xe0000000)
|
||||
|
|
@ -360,12 +363,12 @@ set_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
|
|||
if (thumb) {
|
||||
u16 *ip = (u16 *)asi->insn;
|
||||
if (is_wide_instruction(insn))
|
||||
*ip++ = insn >> 16;
|
||||
*ip++ = insn;
|
||||
*ip++ = __opcode_to_mem_thumb16(insn >> 16);
|
||||
*ip++ = __opcode_to_mem_thumb16(insn);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
asi->insn[0] = insn;
|
||||
asi->insn[0] = __opcode_to_mem_arm(insn);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -163,9 +163,9 @@ t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi)
|
|||
enum kprobe_insn ret = kprobe_decode_ldmstm(insn, asi);
|
||||
|
||||
/* Fixup modified instruction to have halfwords in correct order...*/
|
||||
insn = asi->insn[0];
|
||||
((u16 *)asi->insn)[0] = insn >> 16;
|
||||
((u16 *)asi->insn)[1] = insn & 0xffff;
|
||||
insn = __mem_to_opcode_arm(asi->insn[0]);
|
||||
((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn >> 16);
|
||||
((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0xffff);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1153,7 +1153,7 @@ t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi)
|
|||
{
|
||||
insn &= ~0x00ff;
|
||||
insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */
|
||||
((u16 *)asi->insn)[0] = insn;
|
||||
((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn);
|
||||
asi->insn_handler = t16_emulate_hiregs;
|
||||
return INSN_GOOD;
|
||||
}
|
||||
|
|
@ -1182,8 +1182,10 @@ t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi)
|
|||
* and call it with R9=SP and LR in the register list represented
|
||||
* by R8.
|
||||
*/
|
||||
((u16 *)asi->insn)[0] = 0xe929; /* 1st half STMDB R9!,{} */
|
||||
((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */
|
||||
/* 1st half STMDB R9!,{} */
|
||||
((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe929);
|
||||
/* 2nd half (register list) */
|
||||
((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff);
|
||||
asi->insn_handler = t16_emulate_push;
|
||||
return INSN_GOOD;
|
||||
}
|
||||
|
|
@ -1232,8 +1234,10 @@ t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi)
|
|||
* and call it with R9=SP and PC in the register list represented
|
||||
* by R8.
|
||||
*/
|
||||
((u16 *)asi->insn)[0] = 0xe8b9; /* 1st half LDMIA R9!,{} */
|
||||
((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */
|
||||
/* 1st half LDMIA R9!,{} */
|
||||
((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe8b9);
|
||||
/* 2nd half (register list) */
|
||||
((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff);
|
||||
asi->insn_handler = insn & 0x100 ? t16_emulate_pop_pc
|
||||
: t16_emulate_pop_nopc;
|
||||
return INSN_GOOD;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/stop_machine.h>
|
||||
#include <linux/stringify.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/opcodes.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
#include "kprobes.h"
|
||||
|
|
@ -62,10 +63,10 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
|
|||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
thumb = true;
|
||||
addr &= ~1; /* Bit 0 would normally be set to indicate Thumb code */
|
||||
insn = ((u16 *)addr)[0];
|
||||
insn = __mem_to_opcode_thumb16(((u16 *)addr)[0]);
|
||||
if (is_wide_instruction(insn)) {
|
||||
insn <<= 16;
|
||||
insn |= ((u16 *)addr)[1];
|
||||
u16 inst2 = __mem_to_opcode_thumb16(((u16 *)addr)[1]);
|
||||
insn = __opcode_thumb32_compose(insn, inst2);
|
||||
decode_insn = thumb32_kprobe_decode_insn;
|
||||
} else
|
||||
decode_insn = thumb16_kprobe_decode_insn;
|
||||
|
|
@ -73,7 +74,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
|
|||
thumb = false;
|
||||
if (addr & 0x3)
|
||||
return -EINVAL;
|
||||
insn = *p->addr;
|
||||
insn = __mem_to_opcode_arm(*p->addr);
|
||||
decode_insn = arm_kprobe_decode_insn;
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -14,10 +14,11 @@
|
|||
#include <asm/pgalloc.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/fncpy.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/system_misc.h>
|
||||
|
||||
extern const unsigned char relocate_new_kernel[];
|
||||
extern void relocate_new_kernel(void);
|
||||
extern const unsigned int relocate_new_kernel_size;
|
||||
|
||||
extern unsigned long kexec_start_address;
|
||||
|
|
@ -133,6 +134,8 @@ void machine_kexec(struct kimage *image)
|
|||
{
|
||||
unsigned long page_list;
|
||||
unsigned long reboot_code_buffer_phys;
|
||||
unsigned long reboot_entry = (unsigned long)relocate_new_kernel;
|
||||
unsigned long reboot_entry_phys;
|
||||
void *reboot_code_buffer;
|
||||
|
||||
if (num_online_cpus() > 1) {
|
||||
|
|
@ -156,18 +159,18 @@ void machine_kexec(struct kimage *image)
|
|||
|
||||
|
||||
/* copy our kernel relocation code to the control code page */
|
||||
memcpy(reboot_code_buffer,
|
||||
relocate_new_kernel, relocate_new_kernel_size);
|
||||
reboot_entry = fncpy(reboot_code_buffer,
|
||||
reboot_entry,
|
||||
relocate_new_kernel_size);
|
||||
reboot_entry_phys = (unsigned long)reboot_entry +
|
||||
(reboot_code_buffer_phys - (unsigned long)reboot_code_buffer);
|
||||
|
||||
|
||||
flush_icache_range((unsigned long) reboot_code_buffer,
|
||||
(unsigned long) reboot_code_buffer + KEXEC_CONTROL_PAGE_SIZE);
|
||||
printk(KERN_INFO "Bye!\n");
|
||||
|
||||
if (kexec_reinit)
|
||||
kexec_reinit();
|
||||
|
||||
soft_restart(reboot_code_buffer_phys);
|
||||
soft_restart(reboot_entry_phys);
|
||||
}
|
||||
|
||||
void arch_crash_save_vmcoreinfo(void)
|
||||
|
|
|
|||
|
|
@ -235,49 +235,39 @@ static struct platform_device_id cpu_pmu_plat_device_ids[] = {
|
|||
static int probe_current_pmu(struct arm_pmu *pmu)
|
||||
{
|
||||
int cpu = get_cpu();
|
||||
unsigned long implementor = read_cpuid_implementor();
|
||||
unsigned long part_number = read_cpuid_part_number();
|
||||
int ret = -ENODEV;
|
||||
|
||||
pr_info("probing PMU on CPU %d\n", cpu);
|
||||
|
||||
switch (read_cpuid_part()) {
|
||||
/* ARM Ltd CPUs. */
|
||||
if (implementor == ARM_CPU_IMP_ARM) {
|
||||
switch (part_number) {
|
||||
case ARM_CPU_PART_ARM1136:
|
||||
case ARM_CPU_PART_ARM1156:
|
||||
case ARM_CPU_PART_ARM1176:
|
||||
ret = armv6pmu_init(pmu);
|
||||
break;
|
||||
case ARM_CPU_PART_ARM11MPCORE:
|
||||
ret = armv6mpcore_pmu_init(pmu);
|
||||
break;
|
||||
case ARM_CPU_PART_CORTEX_A8:
|
||||
ret = armv7_a8_pmu_init(pmu);
|
||||
break;
|
||||
case ARM_CPU_PART_CORTEX_A9:
|
||||
ret = armv7_a9_pmu_init(pmu);
|
||||
break;
|
||||
case ARM_CPU_PART_CORTEX_A5:
|
||||
ret = armv7_a5_pmu_init(pmu);
|
||||
break;
|
||||
case ARM_CPU_PART_CORTEX_A15:
|
||||
ret = armv7_a15_pmu_init(pmu);
|
||||
break;
|
||||
case ARM_CPU_PART_CORTEX_A7:
|
||||
ret = armv7_a7_pmu_init(pmu);
|
||||
break;
|
||||
}
|
||||
/* Intel CPUs [xscale]. */
|
||||
} else if (implementor == ARM_CPU_IMP_INTEL) {
|
||||
switch (xscale_cpu_arch_version()) {
|
||||
case ARM_CPU_XSCALE_ARCH_V1:
|
||||
ret = xscale1pmu_init(pmu);
|
||||
break;
|
||||
case ARM_CPU_XSCALE_ARCH_V2:
|
||||
ret = xscale2pmu_init(pmu);
|
||||
break;
|
||||
case ARM_CPU_PART_ARM1136:
|
||||
case ARM_CPU_PART_ARM1156:
|
||||
case ARM_CPU_PART_ARM1176:
|
||||
ret = armv6pmu_init(pmu);
|
||||
break;
|
||||
case ARM_CPU_PART_ARM11MPCORE:
|
||||
ret = armv6mpcore_pmu_init(pmu);
|
||||
break;
|
||||
case ARM_CPU_PART_CORTEX_A8:
|
||||
ret = armv7_a8_pmu_init(pmu);
|
||||
break;
|
||||
case ARM_CPU_PART_CORTEX_A9:
|
||||
ret = armv7_a9_pmu_init(pmu);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (read_cpuid_implementor() == ARM_CPU_IMP_INTEL) {
|
||||
switch (xscale_cpu_arch_version()) {
|
||||
case ARM_CPU_XSCALE_ARCH_V1:
|
||||
ret = xscale1pmu_init(pmu);
|
||||
break;
|
||||
case ARM_CPU_XSCALE_ARCH_V2:
|
||||
ret = xscale2pmu_init(pmu);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* assume PMU support all the CPUs in this case */
|
||||
|
|
|
|||
|
|
@ -916,7 +916,7 @@ enum ptrace_syscall_dir {
|
|||
PTRACE_SYSCALL_EXIT,
|
||||
};
|
||||
|
||||
static int tracehook_report_syscall(struct pt_regs *regs,
|
||||
static void tracehook_report_syscall(struct pt_regs *regs,
|
||||
enum ptrace_syscall_dir dir)
|
||||
{
|
||||
unsigned long ip;
|
||||
|
|
@ -934,7 +934,6 @@ static int tracehook_report_syscall(struct pt_regs *regs,
|
|||
current_thread_info()->syscall = -1;
|
||||
|
||||
regs->ARM_ip = ip;
|
||||
return current_thread_info()->syscall;
|
||||
}
|
||||
|
||||
asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
|
||||
|
|
@ -946,7 +945,9 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
|
|||
return -1;
|
||||
|
||||
if (test_thread_flag(TIF_SYSCALL_TRACE))
|
||||
scno = tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER);
|
||||
tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER);
|
||||
|
||||
scno = current_thread_info()->syscall;
|
||||
|
||||
if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
|
||||
trace_sys_enter(regs, scno);
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@
|
|||
* relocate_kernel.S - put the kernel image in place to boot
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/kexec.h>
|
||||
|
||||
.globl relocate_new_kernel
|
||||
relocate_new_kernel:
|
||||
.align 3 /* not needed for this code, but keeps fncpy() happy */
|
||||
|
||||
ENTRY(relocate_new_kernel)
|
||||
|
||||
ldr r0,kexec_indirection_page
|
||||
ldr r1,kexec_start_address
|
||||
|
|
@ -79,6 +81,8 @@ kexec_mach_type:
|
|||
kexec_boot_atags:
|
||||
.long 0x0
|
||||
|
||||
ENDPROC(relocate_new_kernel)
|
||||
|
||||
relocate_new_kernel_end:
|
||||
|
||||
.globl relocate_new_kernel_size
|
||||
|
|
|
|||
|
|
@ -92,8 +92,8 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
|
|||
* its stack and the page tables.
|
||||
*/
|
||||
secondary_data.stack = task_stack_page(idle) + THREAD_START_SP;
|
||||
secondary_data.pgdir = virt_to_phys(idmap_pgd);
|
||||
secondary_data.swapper_pg_dir = virt_to_phys(swapper_pg_dir);
|
||||
secondary_data.pgdir = virt_to_idmap(idmap_pgd);
|
||||
secondary_data.swapper_pg_dir = virt_to_idmap(swapper_pg_dir);
|
||||
__cpuc_flush_dcache_area(&secondary_data, sizeof(secondary_data));
|
||||
outer_clean_range(__pa(&secondary_data), __pa(&secondary_data + 1));
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ config KVM
|
|||
bool "Kernel-based Virtual Machine (KVM) support"
|
||||
select PREEMPT_NOTIFIERS
|
||||
select ANON_INODES
|
||||
select HAVE_KVM_CPU_RELAX_INTERCEPT
|
||||
select KVM_MMIO
|
||||
select KVM_ARM_HOST
|
||||
depends on ARM_VIRT_EXT && ARM_LPAE
|
||||
|
|
@ -41,9 +42,9 @@ config KVM_ARM_HOST
|
|||
Provides host support for ARM processors.
|
||||
|
||||
config KVM_ARM_MAX_VCPUS
|
||||
int "Number maximum supported virtual CPUs per VM" if KVM_ARM_HOST
|
||||
default 4 if KVM_ARM_HOST
|
||||
default 0
|
||||
int "Number maximum supported virtual CPUs per VM"
|
||||
depends on KVM_ARM_HOST
|
||||
default 4
|
||||
help
|
||||
Static number of max supported virtual CPUs per VM.
|
||||
|
||||
|
|
@ -67,6 +68,4 @@ config KVM_ARM_TIMER
|
|||
---help---
|
||||
Adds support for the Architected Timers in virtual machines
|
||||
|
||||
source drivers/virtio/Kconfig
|
||||
|
||||
endif # VIRTUALIZATION
|
||||
|
|
|
|||
|
|
@ -14,10 +14,12 @@ CFLAGS_mmu.o := -I.
|
|||
AFLAGS_init.o := -Wa,-march=armv7-a$(plus_virt)
|
||||
AFLAGS_interrupts.o := -Wa,-march=armv7-a$(plus_virt)
|
||||
|
||||
kvm-arm-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o)
|
||||
KVM := ../../../virt/kvm
|
||||
kvm-arm-y = $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o
|
||||
|
||||
obj-y += kvm-arm.o init.o interrupts.o
|
||||
obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o
|
||||
obj-y += coproc.o coproc_a15.o mmio.o psci.o perf.o
|
||||
obj-$(CONFIG_KVM_ARM_VGIC) += vgic.o
|
||||
obj-$(CONFIG_KVM_ARM_TIMER) += arch_timer.o
|
||||
obj-y += coproc.o coproc_a15.o coproc_a7.o mmio.o psci.o perf.o
|
||||
obj-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o
|
||||
obj-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2.o
|
||||
obj-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o
|
||||
|
|
|
|||
|
|
@ -82,12 +82,12 @@ struct kvm_vcpu *kvm_arm_get_running_vcpu(void)
|
|||
/**
|
||||
* kvm_arm_get_running_vcpus - get the per-CPU array of currently running vcpus.
|
||||
*/
|
||||
struct kvm_vcpu __percpu **kvm_get_running_vcpus(void)
|
||||
struct kvm_vcpu * __percpu *kvm_get_running_vcpus(void)
|
||||
{
|
||||
return &kvm_arm_running_vcpu;
|
||||
}
|
||||
|
||||
int kvm_arch_hardware_enable(void *garbage)
|
||||
int kvm_arch_hardware_enable(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -97,27 +97,16 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
|
|||
return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
|
||||
}
|
||||
|
||||
void kvm_arch_hardware_disable(void *garbage)
|
||||
{
|
||||
}
|
||||
|
||||
int kvm_arch_hardware_setup(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kvm_arch_hardware_unsetup(void)
|
||||
{
|
||||
}
|
||||
|
||||
void kvm_arch_check_processor_compat(void *rtn)
|
||||
{
|
||||
*(int *)rtn = 0;
|
||||
}
|
||||
|
||||
void kvm_arch_sync_events(struct kvm *kvm)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_arch_init_vm - initializes a VM data structure
|
||||
|
|
@ -138,6 +127,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
|
|||
if (ret)
|
||||
goto out_free_stage2_pgd;
|
||||
|
||||
kvm_timer_init(kvm);
|
||||
|
||||
/* Mark the initial VMID generation invalid */
|
||||
kvm->arch.vmid_gen = 0;
|
||||
|
||||
|
|
@ -153,15 +144,6 @@ int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
|
|||
return VM_FAULT_SIGBUS;
|
||||
}
|
||||
|
||||
void kvm_arch_free_memslot(struct kvm_memory_slot *free,
|
||||
struct kvm_memory_slot *dont)
|
||||
{
|
||||
}
|
||||
|
||||
int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_arch_destroy_vm - destroy the VM data structure
|
||||
|
|
@ -179,20 +161,25 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
|
|||
kvm->vcpus[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
kvm_vgic_destroy(kvm);
|
||||
}
|
||||
|
||||
int kvm_dev_ioctl_check_extension(long ext)
|
||||
int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
||||
{
|
||||
int r;
|
||||
switch (ext) {
|
||||
case KVM_CAP_IRQCHIP:
|
||||
r = vgic_present;
|
||||
break;
|
||||
case KVM_CAP_DEVICE_CTRL:
|
||||
case KVM_CAP_USER_MEMORY:
|
||||
case KVM_CAP_SYNC_MMU:
|
||||
case KVM_CAP_DESTROY_MEMORY_REGION_WORKS:
|
||||
case KVM_CAP_ONE_REG:
|
||||
case KVM_CAP_ARM_PSCI:
|
||||
case KVM_CAP_ARM_PSCI_0_2:
|
||||
case KVM_CAP_READONLY_MEM:
|
||||
r = 1;
|
||||
break;
|
||||
case KVM_CAP_COALESCED_MMIO:
|
||||
|
|
@ -220,29 +207,6 @@ long kvm_arch_dev_ioctl(struct file *filp,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
int kvm_arch_prepare_memory_region(struct kvm *kvm,
|
||||
struct kvm_memory_slot *memslot,
|
||||
struct kvm_userspace_memory_region *mem,
|
||||
enum kvm_mr_change change)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kvm_arch_commit_memory_region(struct kvm *kvm,
|
||||
struct kvm_userspace_memory_region *mem,
|
||||
const struct kvm_memory_slot *old,
|
||||
enum kvm_mr_change change)
|
||||
{
|
||||
}
|
||||
|
||||
void kvm_arch_flush_shadow_all(struct kvm *kvm)
|
||||
{
|
||||
}
|
||||
|
||||
void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
|
||||
struct kvm_memory_slot *slot)
|
||||
{
|
||||
}
|
||||
|
||||
struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
|
||||
{
|
||||
|
|
@ -281,6 +245,7 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
|
|||
{
|
||||
kvm_mmu_free_memory_caches(vcpu);
|
||||
kvm_timer_vcpu_terminate(vcpu);
|
||||
kvm_vgic_vcpu_destroy(vcpu);
|
||||
kmem_cache_free(kvm_vcpu_cache, vcpu);
|
||||
}
|
||||
|
||||
|
|
@ -296,26 +261,15 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
|
|||
|
||||
int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Force users to call KVM_ARM_VCPU_INIT */
|
||||
vcpu->arch.target = -1;
|
||||
|
||||
/* Set up VGIC */
|
||||
ret = kvm_vgic_vcpu_init(vcpu);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set up the timer */
|
||||
kvm_timer_vcpu_init(vcpu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
}
|
||||
|
||||
void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
|
||||
{
|
||||
vcpu->cpu = cpu;
|
||||
|
|
@ -335,6 +289,13 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
|
|||
|
||||
void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/*
|
||||
* The arch-generic KVM code expects the cpu field of a vcpu to be -1
|
||||
* if the vcpu is no longer assigned to a cpu. This is used for the
|
||||
* optimized make_all_cpus_request path.
|
||||
*/
|
||||
vcpu->cpu = -1;
|
||||
|
||||
kvm_arm_set_running_vcpu(NULL);
|
||||
}
|
||||
|
||||
|
|
@ -449,15 +410,17 @@ static void update_vttbr(struct kvm *kvm)
|
|||
|
||||
/* update vttbr to be used with the new vmid */
|
||||
pgd_phys = virt_to_phys(kvm->arch.pgd);
|
||||
BUG_ON(pgd_phys & ~VTTBR_BADDR_MASK);
|
||||
vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & VTTBR_VMID_MASK;
|
||||
kvm->arch.vttbr = pgd_phys & VTTBR_BADDR_MASK;
|
||||
kvm->arch.vttbr |= vmid;
|
||||
kvm->arch.vttbr = pgd_phys | vmid;
|
||||
|
||||
spin_unlock(&kvm_vmid_lock);
|
||||
}
|
||||
|
||||
static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (likely(vcpu->arch.has_run_once))
|
||||
return 0;
|
||||
|
||||
|
|
@ -467,22 +430,12 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
|
|||
* Initialize the VGIC before running a vcpu the first time on
|
||||
* this VM.
|
||||
*/
|
||||
if (irqchip_in_kernel(vcpu->kvm) &&
|
||||
unlikely(!vgic_initialized(vcpu->kvm))) {
|
||||
int ret = kvm_vgic_init(vcpu->kvm);
|
||||
if (unlikely(!vgic_initialized(vcpu->kvm))) {
|
||||
ret = kvm_vgic_init(vcpu->kvm);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the "start in power-off" case by calling into the
|
||||
* PSCI code.
|
||||
*/
|
||||
if (test_and_clear_bit(KVM_ARM_VCPU_POWER_OFF, vcpu->arch.features)) {
|
||||
*vcpu_reg(vcpu, 0) = KVM_PSCI_FN_CPU_OFF;
|
||||
kvm_psci_call(vcpu);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -696,6 +649,24 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu,
|
||||
struct kvm_vcpu_init *init)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = kvm_vcpu_set_target(vcpu, init);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Handle the "start in power-off" case by marking the VCPU as paused.
|
||||
*/
|
||||
if (__test_and_clear_bit(KVM_ARM_VCPU_POWER_OFF, vcpu->arch.features))
|
||||
vcpu->arch.pause = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long kvm_arch_vcpu_ioctl(struct file *filp,
|
||||
unsigned int ioctl, unsigned long arg)
|
||||
{
|
||||
|
|
@ -709,8 +680,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
|
|||
if (copy_from_user(&init, argp, sizeof(init)))
|
||||
return -EFAULT;
|
||||
|
||||
return kvm_vcpu_set_target(vcpu, &init);
|
||||
|
||||
return kvm_arch_vcpu_ioctl_vcpu_init(vcpu, &init);
|
||||
}
|
||||
case KVM_SET_ONE_REG:
|
||||
case KVM_GET_ONE_REG: {
|
||||
|
|
@ -768,7 +738,7 @@ static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
|
|||
case KVM_ARM_DEVICE_VGIC_V2:
|
||||
if (!vgic_present)
|
||||
return -ENXIO;
|
||||
return kvm_vgic_set_addr(kvm, type, dev_addr->addr);
|
||||
return kvm_vgic_addr(kvm, type, &dev_addr->addr, true);
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
@ -794,6 +764,19 @@ long kvm_arch_vm_ioctl(struct file *filp,
|
|||
return -EFAULT;
|
||||
return kvm_vm_ioctl_set_device_addr(kvm, &dev_addr);
|
||||
}
|
||||
case KVM_ARM_PREFERRED_TARGET: {
|
||||
int err;
|
||||
struct kvm_vcpu_init init;
|
||||
|
||||
err = kvm_vcpu_preferred_target(&init);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (copy_to_user(argp, &init, sizeof(init)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -801,8 +784,8 @@ long kvm_arch_vm_ioctl(struct file *filp,
|
|||
|
||||
static void cpu_init_hyp_mode(void *dummy)
|
||||
{
|
||||
unsigned long long boot_pgd_ptr;
|
||||
unsigned long long pgd_ptr;
|
||||
phys_addr_t boot_pgd_ptr;
|
||||
phys_addr_t pgd_ptr;
|
||||
unsigned long hyp_stack_ptr;
|
||||
unsigned long stack_page;
|
||||
unsigned long vector_ptr;
|
||||
|
|
@ -810,8 +793,8 @@ static void cpu_init_hyp_mode(void *dummy)
|
|||
/* Switch from the HYP stub to our own HYP init vector */
|
||||
__hyp_set_vectors(kvm_get_idmap_vector());
|
||||
|
||||
boot_pgd_ptr = (unsigned long long)kvm_mmu_get_boot_httbr();
|
||||
pgd_ptr = (unsigned long long)kvm_mmu_get_httbr();
|
||||
boot_pgd_ptr = kvm_mmu_get_boot_httbr();
|
||||
pgd_ptr = kvm_mmu_get_httbr();
|
||||
stack_page = __get_cpu_var(kvm_arm_hyp_stack_page);
|
||||
hyp_stack_ptr = stack_page + PAGE_SIZE;
|
||||
vector_ptr = (unsigned long)__kvm_hyp_vector;
|
||||
|
|
@ -825,7 +808,8 @@ static int hyp_init_cpu_notify(struct notifier_block *self,
|
|||
switch (action) {
|
||||
case CPU_STARTING:
|
||||
case CPU_STARTING_FROZEN:
|
||||
cpu_init_hyp_mode(NULL);
|
||||
if (__hyp_get_vectors() == hyp_default_vectors)
|
||||
cpu_init_hyp_mode(NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -841,7 +825,8 @@ static int hyp_init_cpu_pm_notifier(struct notifier_block *self,
|
|||
unsigned long cmd,
|
||||
void *v)
|
||||
{
|
||||
if (cmd == CPU_PM_EXIT) {
|
||||
if (cmd == CPU_PM_EXIT &&
|
||||
__hyp_get_vectors() == hyp_default_vectors) {
|
||||
cpu_init_hyp_mode(NULL);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include <asm/kvm_host.h>
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <asm/kvm_coproc.h>
|
||||
#include <asm/kvm_mmu.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/cputype.h>
|
||||
#include <trace/events/kvm.h>
|
||||
|
|
@ -43,6 +44,31 @@ static u32 cache_levels;
|
|||
/* CSSELR values; used to index KVM_REG_ARM_DEMUX_ID_CCSIDR */
|
||||
#define CSSELR_MAX 12
|
||||
|
||||
/*
|
||||
* kvm_vcpu_arch.cp15 holds cp15 registers as an array of u32, but some
|
||||
* of cp15 registers can be viewed either as couple of two u32 registers
|
||||
* or one u64 register. Current u64 register encoding is that least
|
||||
* significant u32 word is followed by most significant u32 word.
|
||||
*/
|
||||
static inline void vcpu_cp15_reg64_set(struct kvm_vcpu *vcpu,
|
||||
const struct coproc_reg *r,
|
||||
u64 val)
|
||||
{
|
||||
vcpu->arch.cp15[r->reg] = val & 0xffffffff;
|
||||
vcpu->arch.cp15[r->reg + 1] = val >> 32;
|
||||
}
|
||||
|
||||
static inline u64 vcpu_cp15_reg64_get(struct kvm_vcpu *vcpu,
|
||||
const struct coproc_reg *r)
|
||||
{
|
||||
u64 val;
|
||||
|
||||
val = vcpu->arch.cp15[r->reg + 1];
|
||||
val = val << 32;
|
||||
val = val | vcpu->arch.cp15[r->reg];
|
||||
return val;
|
||||
}
|
||||
|
||||
int kvm_handle_cp10_id(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
{
|
||||
kvm_inject_undefined(vcpu);
|
||||
|
|
@ -71,6 +97,98 @@ int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void reset_mpidr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
|
||||
{
|
||||
/*
|
||||
* Compute guest MPIDR. We build a virtual cluster out of the
|
||||
* vcpu_id, but we read the 'U' bit from the underlying
|
||||
* hardware directly.
|
||||
*/
|
||||
vcpu->arch.cp15[c0_MPIDR] = ((read_cpuid_mpidr() & MPIDR_SMP_BITMASK) |
|
||||
((vcpu->vcpu_id >> 2) << MPIDR_LEVEL_BITS) |
|
||||
(vcpu->vcpu_id & 3));
|
||||
}
|
||||
|
||||
/* TRM entries A7:4.3.31 A15:4.3.28 - RO WI */
|
||||
static bool access_actlr(struct kvm_vcpu *vcpu,
|
||||
const struct coproc_params *p,
|
||||
const struct coproc_reg *r)
|
||||
{
|
||||
if (p->is_write)
|
||||
return ignore_write(vcpu, p);
|
||||
|
||||
*vcpu_reg(vcpu, p->Rt1) = vcpu->arch.cp15[c1_ACTLR];
|
||||
return true;
|
||||
}
|
||||
|
||||
/* TRM entries A7:4.3.56, A15:4.3.60 - R/O. */
|
||||
static bool access_cbar(struct kvm_vcpu *vcpu,
|
||||
const struct coproc_params *p,
|
||||
const struct coproc_reg *r)
|
||||
{
|
||||
if (p->is_write)
|
||||
return write_to_read_only(vcpu, p);
|
||||
return read_zero(vcpu, p);
|
||||
}
|
||||
|
||||
/* TRM entries A7:4.3.49, A15:4.3.48 - R/O WI */
|
||||
static bool access_l2ctlr(struct kvm_vcpu *vcpu,
|
||||
const struct coproc_params *p,
|
||||
const struct coproc_reg *r)
|
||||
{
|
||||
if (p->is_write)
|
||||
return ignore_write(vcpu, p);
|
||||
|
||||
*vcpu_reg(vcpu, p->Rt1) = vcpu->arch.cp15[c9_L2CTLR];
|
||||
return true;
|
||||
}
|
||||
|
||||
static void reset_l2ctlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
|
||||
{
|
||||
u32 l2ctlr, ncores;
|
||||
|
||||
asm volatile("mrc p15, 1, %0, c9, c0, 2\n" : "=r" (l2ctlr));
|
||||
l2ctlr &= ~(3 << 24);
|
||||
ncores = atomic_read(&vcpu->kvm->online_vcpus) - 1;
|
||||
/* How many cores in the current cluster and the next ones */
|
||||
ncores -= (vcpu->vcpu_id & ~3);
|
||||
/* Cap it to the maximum number of cores in a single cluster */
|
||||
ncores = min(ncores, 3U);
|
||||
l2ctlr |= (ncores & 3) << 24;
|
||||
|
||||
vcpu->arch.cp15[c9_L2CTLR] = l2ctlr;
|
||||
}
|
||||
|
||||
static void reset_actlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
|
||||
{
|
||||
u32 actlr;
|
||||
|
||||
/* ACTLR contains SMP bit: make sure you create all cpus first! */
|
||||
asm volatile("mrc p15, 0, %0, c1, c0, 1\n" : "=r" (actlr));
|
||||
/* Make the SMP bit consistent with the guest configuration */
|
||||
if (atomic_read(&vcpu->kvm->online_vcpus) > 1)
|
||||
actlr |= 1U << 6;
|
||||
else
|
||||
actlr &= ~(1U << 6);
|
||||
|
||||
vcpu->arch.cp15[c1_ACTLR] = actlr;
|
||||
}
|
||||
|
||||
/*
|
||||
* TRM entries: A7:4.3.50, A15:4.3.49
|
||||
* R/O WI (even if NSACR.NS_L2ERR, a write of 1 is ignored).
|
||||
*/
|
||||
static bool access_l2ectlr(struct kvm_vcpu *vcpu,
|
||||
const struct coproc_params *p,
|
||||
const struct coproc_reg *r)
|
||||
{
|
||||
if (p->is_write)
|
||||
return ignore_write(vcpu, p);
|
||||
|
||||
*vcpu_reg(vcpu, p->Rt1) = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* See note at ARM ARM B1.14.4 */
|
||||
static bool access_dcsw(struct kvm_vcpu *vcpu,
|
||||
const struct coproc_params *p,
|
||||
|
|
@ -112,6 +230,44 @@ static bool access_dcsw(struct kvm_vcpu *vcpu,
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic accessor for VM registers. Only called as long as HCR_TVM
|
||||
* is set.
|
||||
*/
|
||||
static bool access_vm_reg(struct kvm_vcpu *vcpu,
|
||||
const struct coproc_params *p,
|
||||
const struct coproc_reg *r)
|
||||
{
|
||||
BUG_ON(!p->is_write);
|
||||
|
||||
vcpu->arch.cp15[r->reg] = *vcpu_reg(vcpu, p->Rt1);
|
||||
if (p->is_64bit)
|
||||
vcpu->arch.cp15[r->reg + 1] = *vcpu_reg(vcpu, p->Rt2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* SCTLR accessor. Only called as long as HCR_TVM is set. If the
|
||||
* guest enables the MMU, we stop trapping the VM sys_regs and leave
|
||||
* it in complete control of the caches.
|
||||
*
|
||||
* Used by the cpu-specific code.
|
||||
*/
|
||||
bool access_sctlr(struct kvm_vcpu *vcpu,
|
||||
const struct coproc_params *p,
|
||||
const struct coproc_reg *r)
|
||||
{
|
||||
access_vm_reg(vcpu, p, r);
|
||||
|
||||
if (vcpu_has_cache_enabled(vcpu)) { /* MMU+Caches enabled? */
|
||||
vcpu->arch.hcr &= ~HCR_TVM;
|
||||
stage2_flush_vm(vcpu->kvm);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* We could trap ID_DFR0 and tell the guest we don't support performance
|
||||
* monitoring. Unfortunately the patch to make the kernel check ID_DFR0 was
|
||||
|
|
@ -153,37 +309,52 @@ static bool pm_fake(struct kvm_vcpu *vcpu,
|
|||
* registers preceding 32-bit ones.
|
||||
*/
|
||||
static const struct coproc_reg cp15_regs[] = {
|
||||
/* MPIDR: we use VMPIDR for guest access. */
|
||||
{ CRn( 0), CRm( 0), Op1( 0), Op2( 5), is32,
|
||||
NULL, reset_mpidr, c0_MPIDR },
|
||||
|
||||
/* CSSELR: swapped by interrupt.S. */
|
||||
{ CRn( 0), CRm( 0), Op1( 2), Op2( 0), is32,
|
||||
NULL, reset_unknown, c0_CSSELR },
|
||||
|
||||
/* TTBR0/TTBR1: swapped by interrupt.S. */
|
||||
{ CRm64( 2), Op1( 0), is64, NULL, reset_unknown64, c2_TTBR0 },
|
||||
{ CRm64( 2), Op1( 1), is64, NULL, reset_unknown64, c2_TTBR1 },
|
||||
/* ACTLR: trapped by HCR.TAC bit. */
|
||||
{ CRn( 1), CRm( 0), Op1( 0), Op2( 1), is32,
|
||||
access_actlr, reset_actlr, c1_ACTLR },
|
||||
|
||||
/* TTBCR: swapped by interrupt.S. */
|
||||
/* CPACR: swapped by interrupt.S. */
|
||||
{ CRn( 1), CRm( 0), Op1( 0), Op2( 2), is32,
|
||||
NULL, reset_val, c1_CPACR, 0x00000000 },
|
||||
|
||||
/* TTBR0/TTBR1/TTBCR: swapped by interrupt.S. */
|
||||
{ CRm64( 2), Op1( 0), is64, access_vm_reg, reset_unknown64, c2_TTBR0 },
|
||||
{ CRn(2), CRm( 0), Op1( 0), Op2( 0), is32,
|
||||
access_vm_reg, reset_unknown, c2_TTBR0 },
|
||||
{ CRn(2), CRm( 0), Op1( 0), Op2( 1), is32,
|
||||
access_vm_reg, reset_unknown, c2_TTBR1 },
|
||||
{ CRn( 2), CRm( 0), Op1( 0), Op2( 2), is32,
|
||||
NULL, reset_val, c2_TTBCR, 0x00000000 },
|
||||
access_vm_reg, reset_val, c2_TTBCR, 0x00000000 },
|
||||
{ CRm64( 2), Op1( 1), is64, access_vm_reg, reset_unknown64, c2_TTBR1 },
|
||||
|
||||
|
||||
/* DACR: swapped by interrupt.S. */
|
||||
{ CRn( 3), CRm( 0), Op1( 0), Op2( 0), is32,
|
||||
NULL, reset_unknown, c3_DACR },
|
||||
access_vm_reg, reset_unknown, c3_DACR },
|
||||
|
||||
/* DFSR/IFSR/ADFSR/AIFSR: swapped by interrupt.S. */
|
||||
{ CRn( 5), CRm( 0), Op1( 0), Op2( 0), is32,
|
||||
NULL, reset_unknown, c5_DFSR },
|
||||
access_vm_reg, reset_unknown, c5_DFSR },
|
||||
{ CRn( 5), CRm( 0), Op1( 0), Op2( 1), is32,
|
||||
NULL, reset_unknown, c5_IFSR },
|
||||
access_vm_reg, reset_unknown, c5_IFSR },
|
||||
{ CRn( 5), CRm( 1), Op1( 0), Op2( 0), is32,
|
||||
NULL, reset_unknown, c5_ADFSR },
|
||||
access_vm_reg, reset_unknown, c5_ADFSR },
|
||||
{ CRn( 5), CRm( 1), Op1( 0), Op2( 1), is32,
|
||||
NULL, reset_unknown, c5_AIFSR },
|
||||
access_vm_reg, reset_unknown, c5_AIFSR },
|
||||
|
||||
/* DFAR/IFAR: swapped by interrupt.S. */
|
||||
{ CRn( 6), CRm( 0), Op1( 0), Op2( 0), is32,
|
||||
NULL, reset_unknown, c6_DFAR },
|
||||
access_vm_reg, reset_unknown, c6_DFAR },
|
||||
{ CRn( 6), CRm( 0), Op1( 0), Op2( 2), is32,
|
||||
NULL, reset_unknown, c6_IFAR },
|
||||
access_vm_reg, reset_unknown, c6_IFAR },
|
||||
|
||||
/* PAR swapped by interrupt.S */
|
||||
{ CRm64( 7), Op1( 0), is64, NULL, reset_unknown64, c7_PAR },
|
||||
|
|
@ -194,6 +365,13 @@ static const struct coproc_reg cp15_regs[] = {
|
|||
{ CRn( 7), CRm( 6), Op1( 0), Op2( 2), is32, access_dcsw},
|
||||
{ CRn( 7), CRm(10), Op1( 0), Op2( 2), is32, access_dcsw},
|
||||
{ CRn( 7), CRm(14), Op1( 0), Op2( 2), is32, access_dcsw},
|
||||
/*
|
||||
* L2CTLR access (guest wants to know #CPUs).
|
||||
*/
|
||||
{ CRn( 9), CRm( 0), Op1( 1), Op2( 2), is32,
|
||||
access_l2ctlr, reset_l2ctlr, c9_L2CTLR },
|
||||
{ CRn( 9), CRm( 0), Op1( 1), Op2( 3), is32, access_l2ectlr},
|
||||
|
||||
/*
|
||||
* Dummy performance monitor implementation.
|
||||
*/
|
||||
|
|
@ -213,9 +391,15 @@ static const struct coproc_reg cp15_regs[] = {
|
|||
|
||||
/* PRRR/NMRR (aka MAIR0/MAIR1): swapped by interrupt.S. */
|
||||
{ CRn(10), CRm( 2), Op1( 0), Op2( 0), is32,
|
||||
NULL, reset_unknown, c10_PRRR},
|
||||
access_vm_reg, reset_unknown, c10_PRRR},
|
||||
{ CRn(10), CRm( 2), Op1( 0), Op2( 1), is32,
|
||||
NULL, reset_unknown, c10_NMRR},
|
||||
access_vm_reg, reset_unknown, c10_NMRR},
|
||||
|
||||
/* AMAIR0/AMAIR1: swapped by interrupt.S. */
|
||||
{ CRn(10), CRm( 3), Op1( 0), Op2( 0), is32,
|
||||
access_vm_reg, reset_unknown, c10_AMAIR0},
|
||||
{ CRn(10), CRm( 3), Op1( 0), Op2( 1), is32,
|
||||
access_vm_reg, reset_unknown, c10_AMAIR1},
|
||||
|
||||
/* VBAR: swapped by interrupt.S. */
|
||||
{ CRn(12), CRm( 0), Op1( 0), Op2( 0), is32,
|
||||
|
|
@ -223,7 +407,7 @@ static const struct coproc_reg cp15_regs[] = {
|
|||
|
||||
/* CONTEXTIDR/TPIDRURW/TPIDRURO/TPIDRPRW: swapped by interrupt.S. */
|
||||
{ CRn(13), CRm( 0), Op1( 0), Op2( 1), is32,
|
||||
NULL, reset_val, c13_CID, 0x00000000 },
|
||||
access_vm_reg, reset_val, c13_CID, 0x00000000 },
|
||||
{ CRn(13), CRm( 0), Op1( 0), Op2( 2), is32,
|
||||
NULL, reset_unknown, c13_TID_URW },
|
||||
{ CRn(13), CRm( 0), Op1( 0), Op2( 3), is32,
|
||||
|
|
@ -234,6 +418,9 @@ static const struct coproc_reg cp15_regs[] = {
|
|||
/* CNTKCTL: swapped by interrupt.S. */
|
||||
{ CRn(14), CRm( 1), Op1( 0), Op2( 0), is32,
|
||||
NULL, reset_val, c14_CNTKCTL, 0x00000000 },
|
||||
|
||||
/* The Configuration Base Address Register. */
|
||||
{ CRn(15), CRm( 0), Op1( 4), Op2( 0), is32, access_cbar},
|
||||
};
|
||||
|
||||
/* Target specific emulation tables */
|
||||
|
|
@ -241,6 +428,12 @@ static struct kvm_coproc_target_table *target_tables[KVM_ARM_NUM_TARGETS];
|
|||
|
||||
void kvm_register_target_coproc_table(struct kvm_coproc_target_table *table)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 1; i < table->num; i++)
|
||||
BUG_ON(cmp_reg(&table->table[i-1],
|
||||
&table->table[i]) >= 0);
|
||||
|
||||
target_tables[table->target] = table;
|
||||
}
|
||||
|
||||
|
|
@ -323,7 +516,7 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||
{
|
||||
struct coproc_params params;
|
||||
|
||||
params.CRm = (kvm_vcpu_get_hsr(vcpu) >> 1) & 0xf;
|
||||
params.CRn = (kvm_vcpu_get_hsr(vcpu) >> 1) & 0xf;
|
||||
params.Rt1 = (kvm_vcpu_get_hsr(vcpu) >> 5) & 0xf;
|
||||
params.is_write = ((kvm_vcpu_get_hsr(vcpu) & 1) == 0);
|
||||
params.is_64bit = true;
|
||||
|
|
@ -331,7 +524,7 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||
params.Op1 = (kvm_vcpu_get_hsr(vcpu) >> 16) & 0xf;
|
||||
params.Op2 = 0;
|
||||
params.Rt2 = (kvm_vcpu_get_hsr(vcpu) >> 10) & 0xf;
|
||||
params.CRn = 0;
|
||||
params.CRm = 0;
|
||||
|
||||
return emulate_cp15(vcpu, ¶ms);
|
||||
}
|
||||
|
|
@ -514,17 +707,23 @@ static struct coproc_reg invariant_cp15[] = {
|
|||
{ CRn( 0), CRm( 0), Op1( 1), Op2( 7), is32, NULL, get_AIDR },
|
||||
};
|
||||
|
||||
/*
|
||||
* Reads a register value from a userspace address to a kernel
|
||||
* variable. Make sure that register size matches sizeof(*__val).
|
||||
*/
|
||||
static int reg_from_user(void *val, const void __user *uaddr, u64 id)
|
||||
{
|
||||
/* This Just Works because we are little endian. */
|
||||
if (copy_from_user(val, uaddr, KVM_REG_SIZE(id)) != 0)
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes a register value to a userspace address from a kernel variable.
|
||||
* Make sure that register size matches sizeof(*__val).
|
||||
*/
|
||||
static int reg_to_user(void __user *uaddr, const void *val, u64 id)
|
||||
{
|
||||
/* This Just Works because we are little endian. */
|
||||
if (copy_to_user(uaddr, val, KVM_REG_SIZE(id)) != 0)
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
|
|
@ -534,6 +733,7 @@ static int get_invariant_cp15(u64 id, void __user *uaddr)
|
|||
{
|
||||
struct coproc_params params;
|
||||
const struct coproc_reg *r;
|
||||
int ret;
|
||||
|
||||
if (!index_to_params(id, ¶ms))
|
||||
return -ENOENT;
|
||||
|
|
@ -542,7 +742,15 @@ static int get_invariant_cp15(u64 id, void __user *uaddr)
|
|||
if (!r)
|
||||
return -ENOENT;
|
||||
|
||||
return reg_to_user(uaddr, &r->val, id);
|
||||
ret = -ENOENT;
|
||||
if (KVM_REG_SIZE(id) == 4) {
|
||||
u32 val = r->val;
|
||||
|
||||
ret = reg_to_user(uaddr, &val, id);
|
||||
} else if (KVM_REG_SIZE(id) == 8) {
|
||||
ret = reg_to_user(uaddr, &r->val, id);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_invariant_cp15(u64 id, void __user *uaddr)
|
||||
|
|
@ -550,7 +758,7 @@ static int set_invariant_cp15(u64 id, void __user *uaddr)
|
|||
struct coproc_params params;
|
||||
const struct coproc_reg *r;
|
||||
int err;
|
||||
u64 val = 0; /* Make sure high bits are 0 for 32-bit regs */
|
||||
u64 val;
|
||||
|
||||
if (!index_to_params(id, ¶ms))
|
||||
return -ENOENT;
|
||||
|
|
@ -558,7 +766,16 @@ static int set_invariant_cp15(u64 id, void __user *uaddr)
|
|||
if (!r)
|
||||
return -ENOENT;
|
||||
|
||||
err = reg_from_user(&val, uaddr, id);
|
||||
err = -ENOENT;
|
||||
if (KVM_REG_SIZE(id) == 4) {
|
||||
u32 val32;
|
||||
|
||||
err = reg_from_user(&val32, uaddr, id);
|
||||
if (!err)
|
||||
val = val32;
|
||||
} else if (KVM_REG_SIZE(id) == 8) {
|
||||
err = reg_from_user(&val, uaddr, id);
|
||||
}
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
@ -574,7 +791,7 @@ static bool is_valid_cache(u32 val)
|
|||
u32 level, ctype;
|
||||
|
||||
if (val >= CSSELR_MAX)
|
||||
return -ENOENT;
|
||||
return false;
|
||||
|
||||
/* Bottom bit is Instruction or Data bit. Next 3 bits are level. */
|
||||
level = (val >> 1);
|
||||
|
|
@ -836,6 +1053,7 @@ int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
|||
{
|
||||
const struct coproc_reg *r;
|
||||
void __user *uaddr = (void __user *)(long)reg->addr;
|
||||
int ret;
|
||||
|
||||
if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX)
|
||||
return demux_c15_get(reg->id, uaddr);
|
||||
|
|
@ -847,14 +1065,24 @@ int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
|||
if (!r)
|
||||
return get_invariant_cp15(reg->id, uaddr);
|
||||
|
||||
/* Note: copies two regs if size is 64 bit. */
|
||||
return reg_to_user(uaddr, &vcpu->arch.cp15[r->reg], reg->id);
|
||||
ret = -ENOENT;
|
||||
if (KVM_REG_SIZE(reg->id) == 8) {
|
||||
u64 val;
|
||||
|
||||
val = vcpu_cp15_reg64_get(vcpu, r);
|
||||
ret = reg_to_user(uaddr, &val, reg->id);
|
||||
} else if (KVM_REG_SIZE(reg->id) == 4) {
|
||||
ret = reg_to_user(uaddr, &vcpu->arch.cp15[r->reg], reg->id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
||||
{
|
||||
const struct coproc_reg *r;
|
||||
void __user *uaddr = (void __user *)(long)reg->addr;
|
||||
int ret;
|
||||
|
||||
if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX)
|
||||
return demux_c15_set(reg->id, uaddr);
|
||||
|
|
@ -866,8 +1094,18 @@ int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
|||
if (!r)
|
||||
return set_invariant_cp15(reg->id, uaddr);
|
||||
|
||||
/* Note: copies two regs if size is 64 bit */
|
||||
return reg_from_user(&vcpu->arch.cp15[r->reg], uaddr, reg->id);
|
||||
ret = -ENOENT;
|
||||
if (KVM_REG_SIZE(reg->id) == 8) {
|
||||
u64 val;
|
||||
|
||||
ret = reg_from_user(&val, uaddr, reg->id);
|
||||
if (!ret)
|
||||
vcpu_cp15_reg64_set(vcpu, r, val);
|
||||
} else if (KVM_REG_SIZE(reg->id) == 4) {
|
||||
ret = reg_from_user(&vcpu->arch.cp15[r->reg], uaddr, reg->id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned int num_demux_regs(void)
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@ 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(" { CRm(%2lu), Op1(%2lu), is64, func_%s },\n",
|
||||
p->CRm, p->Op1, p->is_write ? "write" : "read");
|
||||
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",
|
||||
|
|
@ -135,13 +135,13 @@ static inline int cmp_reg(const struct coproc_reg *i1,
|
|||
return -1;
|
||||
if (i1->CRn != i2->CRn)
|
||||
return i1->CRn - i2->CRn;
|
||||
if (i1->is_64 != i2->is_64)
|
||||
return i2->is_64 - i1->is_64;
|
||||
if (i1->CRm != i2->CRm)
|
||||
return i1->CRm - i2->CRm;
|
||||
if (i1->Op1 != i2->Op1)
|
||||
return i1->Op1 - i2->Op1;
|
||||
return i1->Op2 - i2->Op2;
|
||||
if (i1->Op2 != i2->Op2)
|
||||
return i1->Op2 - i2->Op2;
|
||||
return i2->is_64 - i1->is_64;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -153,4 +153,8 @@ static inline int cmp_reg(const struct coproc_reg *i1,
|
|||
#define is64 .is_64 = true
|
||||
#define is32 .is_64 = false
|
||||
|
||||
bool access_sctlr(struct kvm_vcpu *vcpu,
|
||||
const struct coproc_params *p,
|
||||
const struct coproc_reg *r);
|
||||
|
||||
#endif /* __ARM_KVM_COPROC_LOCAL_H__ */
|
||||
|
|
|
|||
|
|
@ -17,101 +17,12 @@
|
|||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include <linux/kvm_host.h>
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/kvm_arm.h>
|
||||
#include <asm/kvm_host.h>
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <asm/kvm_coproc.h>
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
static void reset_mpidr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
|
||||
{
|
||||
/*
|
||||
* Compute guest MPIDR:
|
||||
* (Even if we present only one VCPU to the guest on an SMP
|
||||
* host we don't set the U bit in the MPIDR, or vice versa, as
|
||||
* revealing the underlying hardware properties is likely to
|
||||
* be the best choice).
|
||||
*/
|
||||
vcpu->arch.cp15[c0_MPIDR] = (read_cpuid_mpidr() & ~MPIDR_LEVEL_MASK)
|
||||
| (vcpu->vcpu_id & MPIDR_LEVEL_MASK);
|
||||
}
|
||||
|
||||
#include "coproc.h"
|
||||
|
||||
/* A15 TRM 4.3.28: RO WI */
|
||||
static bool access_actlr(struct kvm_vcpu *vcpu,
|
||||
const struct coproc_params *p,
|
||||
const struct coproc_reg *r)
|
||||
{
|
||||
if (p->is_write)
|
||||
return ignore_write(vcpu, p);
|
||||
|
||||
*vcpu_reg(vcpu, p->Rt1) = vcpu->arch.cp15[c1_ACTLR];
|
||||
return true;
|
||||
}
|
||||
|
||||
/* A15 TRM 4.3.60: R/O. */
|
||||
static bool access_cbar(struct kvm_vcpu *vcpu,
|
||||
const struct coproc_params *p,
|
||||
const struct coproc_reg *r)
|
||||
{
|
||||
if (p->is_write)
|
||||
return write_to_read_only(vcpu, p);
|
||||
return read_zero(vcpu, p);
|
||||
}
|
||||
|
||||
/* A15 TRM 4.3.48: R/O WI. */
|
||||
static bool access_l2ctlr(struct kvm_vcpu *vcpu,
|
||||
const struct coproc_params *p,
|
||||
const struct coproc_reg *r)
|
||||
{
|
||||
if (p->is_write)
|
||||
return ignore_write(vcpu, p);
|
||||
|
||||
*vcpu_reg(vcpu, p->Rt1) = vcpu->arch.cp15[c9_L2CTLR];
|
||||
return true;
|
||||
}
|
||||
|
||||
static void reset_l2ctlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
|
||||
{
|
||||
u32 l2ctlr, ncores;
|
||||
|
||||
asm volatile("mrc p15, 1, %0, c9, c0, 2\n" : "=r" (l2ctlr));
|
||||
l2ctlr &= ~(3 << 24);
|
||||
ncores = atomic_read(&vcpu->kvm->online_vcpus) - 1;
|
||||
l2ctlr |= (ncores & 3) << 24;
|
||||
|
||||
vcpu->arch.cp15[c9_L2CTLR] = l2ctlr;
|
||||
}
|
||||
|
||||
static void reset_actlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
|
||||
{
|
||||
u32 actlr;
|
||||
|
||||
/* ACTLR contains SMP bit: make sure you create all cpus first! */
|
||||
asm volatile("mrc p15, 0, %0, c1, c0, 1\n" : "=r" (actlr));
|
||||
/* Make the SMP bit consistent with the guest configuration */
|
||||
if (atomic_read(&vcpu->kvm->online_vcpus) > 1)
|
||||
actlr |= 1U << 6;
|
||||
else
|
||||
actlr &= ~(1U << 6);
|
||||
|
||||
vcpu->arch.cp15[c1_ACTLR] = actlr;
|
||||
}
|
||||
|
||||
/* A15 TRM 4.3.49: R/O WI (even if NSACR.NS_L2ERR, a write of 1 is ignored). */
|
||||
static bool access_l2ectlr(struct kvm_vcpu *vcpu,
|
||||
const struct coproc_params *p,
|
||||
const struct coproc_reg *r)
|
||||
{
|
||||
if (p->is_write)
|
||||
return ignore_write(vcpu, p);
|
||||
|
||||
*vcpu_reg(vcpu, p->Rt1) = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* A15-specific CP15 registers.
|
||||
* CRn denotes the primary register number, but is copied to the CRm in the
|
||||
|
|
@ -121,29 +32,9 @@ static bool access_l2ectlr(struct kvm_vcpu *vcpu,
|
|||
* registers preceding 32-bit ones.
|
||||
*/
|
||||
static const struct coproc_reg a15_regs[] = {
|
||||
/* MPIDR: we use VMPIDR for guest access. */
|
||||
{ CRn( 0), CRm( 0), Op1( 0), Op2( 5), is32,
|
||||
NULL, reset_mpidr, c0_MPIDR },
|
||||
|
||||
/* SCTLR: swapped by interrupt.S. */
|
||||
{ CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32,
|
||||
NULL, reset_val, c1_SCTLR, 0x00C50078 },
|
||||
/* ACTLR: trapped by HCR.TAC bit. */
|
||||
{ CRn( 1), CRm( 0), Op1( 0), Op2( 1), is32,
|
||||
access_actlr, reset_actlr, c1_ACTLR },
|
||||
/* CPACR: swapped by interrupt.S. */
|
||||
{ CRn( 1), CRm( 0), Op1( 0), Op2( 2), is32,
|
||||
NULL, reset_val, c1_CPACR, 0x00000000 },
|
||||
|
||||
/*
|
||||
* L2CTLR access (guest wants to know #CPUs).
|
||||
*/
|
||||
{ CRn( 9), CRm( 0), Op1( 1), Op2( 2), is32,
|
||||
access_l2ctlr, reset_l2ctlr, c9_L2CTLR },
|
||||
{ CRn( 9), CRm( 0), Op1( 1), Op2( 3), is32, access_l2ectlr},
|
||||
|
||||
/* The Configuration Base Address Register. */
|
||||
{ CRn(15), CRm( 0), Op1( 4), Op2( 0), is32, access_cbar},
|
||||
access_sctlr, reset_val, c1_SCTLR, 0x00C50078 },
|
||||
};
|
||||
|
||||
static struct kvm_coproc_target_table a15_target_table = {
|
||||
|
|
@ -154,12 +45,6 @@ static struct kvm_coproc_target_table a15_target_table = {
|
|||
|
||||
static int __init coproc_a15_init(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 1; i < ARRAY_SIZE(a15_regs); i++)
|
||||
BUG_ON(cmp_reg(&a15_regs[i-1],
|
||||
&a15_regs[i]) >= 0);
|
||||
|
||||
kvm_register_target_coproc_table(&a15_target_table);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
54
arch/arm/kvm/coproc_a7.c
Normal file
54
arch/arm/kvm/coproc_a7.c
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#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_sctlr, 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);
|
||||
|
|
@ -354,7 +354,7 @@ static void inject_abt(struct kvm_vcpu *vcpu, bool is_pabt, unsigned long addr)
|
|||
*vcpu_pc(vcpu) = exc_vector_base(vcpu) + vect_offset;
|
||||
|
||||
if (is_pabt) {
|
||||
/* Set DFAR and DFSR */
|
||||
/* Set IFAR and IFSR */
|
||||
vcpu->arch.cp15[c6_IFAR] = addr;
|
||||
is_lpae = (vcpu->arch.cp15[c2_TTBCR] >> 31);
|
||||
/* Always give debug fault for now - should give guest a clue */
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
|
|||
|
||||
int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
vcpu->arch.hcr = HCR_GUEST_MASK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -109,6 +110,73 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_KVM_ARM_TIMER
|
||||
|
||||
#define NUM_TIMER_REGS 0
|
||||
|
||||
static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool is_timer_reg(u64 index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
static unsigned long num_core_regs(void)
|
||||
{
|
||||
return sizeof(struct kvm_regs) / sizeof(u32);
|
||||
|
|
@ -121,7 +189,8 @@ static unsigned long num_core_regs(void)
|
|||
*/
|
||||
unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return num_core_regs() + kvm_arm_num_coproc_regs(vcpu);
|
||||
return num_core_regs() + kvm_arm_num_coproc_regs(vcpu)
|
||||
+ NUM_TIMER_REGS;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -133,6 +202,7 @@ 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))
|
||||
|
|
@ -140,6 +210,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
|
|||
uindices++;
|
||||
}
|
||||
|
||||
ret = copy_timer_indices(vcpu, uindices);
|
||||
if (ret)
|
||||
return ret;
|
||||
uindices += NUM_TIMER_REGS;
|
||||
|
||||
return kvm_arm_copy_coproc_indices(vcpu, uindices);
|
||||
}
|
||||
|
||||
|
|
@ -153,6 +228,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
|||
if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
|
||||
return get_core_reg(vcpu, reg);
|
||||
|
||||
if (is_timer_reg(reg->id))
|
||||
return get_timer_reg(vcpu, reg);
|
||||
|
||||
return kvm_arm_coproc_get_reg(vcpu, reg);
|
||||
}
|
||||
|
||||
|
|
@ -166,6 +244,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
|||
if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
|
||||
return set_core_reg(vcpu, reg);
|
||||
|
||||
if (is_timer_reg(reg->id))
|
||||
return set_timer_reg(vcpu, reg);
|
||||
|
||||
return kvm_arm_coproc_set_reg(vcpu, reg);
|
||||
}
|
||||
|
||||
|
|
@ -183,13 +264,9 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
|
|||
|
||||
int __attribute_const__ kvm_target_cpu(void)
|
||||
{
|
||||
unsigned long implementor = read_cpuid_implementor();
|
||||
unsigned long part_number = read_cpuid_part_number();
|
||||
|
||||
if (implementor != ARM_CPU_IMP_ARM)
|
||||
return -EINVAL;
|
||||
|
||||
switch (part_number) {
|
||||
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:
|
||||
|
|
@ -202,7 +279,7 @@ int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
|
|||
{
|
||||
unsigned int i;
|
||||
|
||||
/* We can only do a cortex A15 for now. */
|
||||
/* We can only cope with guest==host and only on A15/A7 (for now). */
|
||||
if (init->target != kvm_target_cpu())
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -222,6 +299,26 @@ int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
|
|||
return kvm_reset_vcpu(vcpu);
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -26,8 +26,6 @@
|
|||
|
||||
#include "trace.h"
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
typedef int (*exit_handle_fn)(struct kvm_vcpu *, struct kvm_run *);
|
||||
|
||||
static int handle_svc_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
|
|
@ -40,21 +38,22 @@ static int handle_svc_hyp(struct kvm_vcpu *vcpu, struct kvm_run *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));
|
||||
|
||||
if (kvm_psci_call(vcpu))
|
||||
ret = kvm_psci_call(vcpu);
|
||||
if (ret < 0) {
|
||||
kvm_inject_undefined(vcpu);
|
||||
return 1;
|
||||
}
|
||||
|
||||
kvm_inject_undefined(vcpu);
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
{
|
||||
if (kvm_psci_call(vcpu))
|
||||
return 1;
|
||||
|
||||
kvm_inject_undefined(vcpu);
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -76,23 +75,29 @@ static int handle_dabt_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||
}
|
||||
|
||||
/**
|
||||
* kvm_handle_wfi - handle a wait-for-interrupts instruction executed by a guest
|
||||
* kvm_handle_wfx - handle a WFI or WFE instructions trapped in guests
|
||||
* @vcpu: the vcpu pointer
|
||||
* @run: the kvm_run structure pointer
|
||||
*
|
||||
* Simply sets the wait_for_interrupts flag on the vcpu structure, which will
|
||||
* halt execution of world-switches and schedule other host processes until
|
||||
* there is an incoming IRQ or FIQ to the VM.
|
||||
* 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_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
{
|
||||
trace_kvm_wfi(*vcpu_pc(vcpu));
|
||||
kvm_vcpu_block(vcpu);
|
||||
if (kvm_vcpu_get_hsr(vcpu) & HSR_WFI_IS_WFE)
|
||||
kvm_vcpu_on_spin(vcpu);
|
||||
else
|
||||
kvm_vcpu_block(vcpu);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static exit_handle_fn arm_exit_handlers[] = {
|
||||
[HSR_EC_WFI] = kvm_handle_wfi,
|
||||
[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_access,
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ __do_hyp_init:
|
|||
bne phase2 @ Yes, second stage init
|
||||
|
||||
@ Set the HTTBR to point to the hypervisor PGD pointer passed
|
||||
mcrr p15, 4, r2, r3, c2
|
||||
mcrr p15, 4, rr_lo_hi(r2, r3), c2
|
||||
|
||||
@ Set the HTCR and VTCR to the same shareability and cacheability
|
||||
@ settings as the non-secure TTBCR and with T0SZ == 0.
|
||||
|
|
@ -137,12 +137,12 @@ phase2:
|
|||
mov pc, r0
|
||||
|
||||
target: @ We're now in the trampoline code, switch page tables
|
||||
mcrr p15, 4, r2, r3, c2
|
||||
mcrr p15, 4, rr_lo_hi(r2, r3), c2
|
||||
isb
|
||||
|
||||
@ Invalidate the old TLBs
|
||||
mcr p15, 4, r0, c8, c7, 0 @ TLBIALLH
|
||||
dsb
|
||||
dsb ish
|
||||
|
||||
eret
|
||||
|
||||
|
|
|
|||
|
|
@ -52,10 +52,10 @@ ENTRY(__kvm_tlb_flush_vmid_ipa)
|
|||
dsb ishst
|
||||
add r0, r0, #KVM_VTTBR
|
||||
ldrd r2, r3, [r0]
|
||||
mcrr p15, 6, r2, r3, c2 @ Write VTTBR
|
||||
mcrr p15, 6, rr_lo_hi(r2, r3), c2 @ Write VTTBR
|
||||
isb
|
||||
mcr p15, 0, r0, c8, c3, 0 @ TLBIALLIS (rt ignored)
|
||||
dsb
|
||||
dsb ish
|
||||
isb
|
||||
mov r2, #0
|
||||
mov r3, #0
|
||||
|
|
@ -79,7 +79,7 @@ ENTRY(__kvm_flush_vm_context)
|
|||
mcr p15, 4, r0, c8, c3, 4
|
||||
/* Invalidate instruction caches Inner Shareable (ICIALLUIS) */
|
||||
mcr p15, 0, r0, c7, c1, 0
|
||||
dsb
|
||||
dsb ish
|
||||
isb @ Not necessary if followed by eret
|
||||
|
||||
bx lr
|
||||
|
|
@ -135,7 +135,7 @@ ENTRY(__kvm_vcpu_run)
|
|||
ldr r1, [vcpu, #VCPU_KVM]
|
||||
add r1, r1, #KVM_VTTBR
|
||||
ldrd r2, r3, [r1]
|
||||
mcrr p15, 6, r2, r3, c2 @ Write VTTBR
|
||||
mcrr p15, 6, rr_lo_hi(r2, r3), c2 @ Write VTTBR
|
||||
|
||||
@ We're all done, just restore the GPRs and go to the guest
|
||||
restore_guest_regs
|
||||
|
|
@ -199,8 +199,13 @@ after_vfp_restore:
|
|||
|
||||
restore_host_regs
|
||||
clrex @ Clear exclusive monitor
|
||||
#ifndef CONFIG_CPU_ENDIAN_BE8
|
||||
mov r0, r1 @ Return the return code
|
||||
mov r1, #0 @ Clear upper bits in return value
|
||||
#else
|
||||
@ r1 already has return code
|
||||
mov r0, #0 @ Clear upper bits in return value
|
||||
#endif /* CONFIG_CPU_ENDIAN_BE8 */
|
||||
bx lr @ return to IOCTL
|
||||
|
||||
/********************************************************************
|
||||
|
|
@ -220,6 +225,10 @@ after_vfp_restore:
|
|||
* in Hyp mode (see init_hyp_mode in arch/arm/kvm/arm.c). Return values are
|
||||
* passed in r0 and r1.
|
||||
*
|
||||
* A function pointer with a value of 0xffffffff has a special meaning,
|
||||
* and is used to implement __hyp_get_vectors in the same way as in
|
||||
* arch/arm/kernel/hyp_stub.S.
|
||||
*
|
||||
* The calling convention follows the standard AAPCS:
|
||||
* r0 - r3: caller save
|
||||
* r12: caller save
|
||||
|
|
@ -363,6 +372,11 @@ hyp_hvc:
|
|||
host_switch_to_hyp:
|
||||
pop {r0, r1, r2}
|
||||
|
||||
/* Check for __hyp_get_vectors */
|
||||
cmp r0, #-1
|
||||
mrceq p15, 4, r0, c12, c0, 0 @ get HVBAR
|
||||
beq 1f
|
||||
|
||||
push {lr}
|
||||
mrs lr, SPSR
|
||||
push {lr}
|
||||
|
|
@ -378,7 +392,7 @@ THUMB( orr lr, #1)
|
|||
pop {lr}
|
||||
msr SPSR_csxf, lr
|
||||
pop {lr}
|
||||
eret
|
||||
1: eret
|
||||
|
||||
guest_trap:
|
||||
load_vcpu @ Load VCPU pointer to r0
|
||||
|
|
@ -492,10 +506,10 @@ __kvm_hyp_code_end:
|
|||
.section ".rodata"
|
||||
|
||||
und_die_str:
|
||||
.ascii "unexpected undefined exception in Hyp mode at: %#08x"
|
||||
.ascii "unexpected undefined exception in Hyp mode at: %#08x\n"
|
||||
pabt_die_str:
|
||||
.ascii "unexpected prefetch abort in Hyp mode at: %#08x"
|
||||
.ascii "unexpected prefetch abort in Hyp mode at: %#08x\n"
|
||||
dabt_die_str:
|
||||
.ascii "unexpected data abort in Hyp mode at: %#08x"
|
||||
.ascii "unexpected data abort in Hyp mode at: %#08x\n"
|
||||
svc_die_str:
|
||||
.ascii "unexpected HVC/SVC trap in Hyp mode at: %#08x"
|
||||
.ascii "unexpected HVC/SVC trap in Hyp mode at: %#08x\n"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include <linux/irqchip/arm-gic.h>
|
||||
#include <asm/assembler.h>
|
||||
|
||||
#define VCPU_USR_REG(_reg_nr) (VCPU_USR_REGS + (_reg_nr * 4))
|
||||
#define VCPU_USR_SP (VCPU_USR_REG(13))
|
||||
|
|
@ -303,13 +304,17 @@ vcpu .req r0 @ vcpu pointer always in r0
|
|||
|
||||
mrc p15, 0, r2, c14, c1, 0 @ CNTKCTL
|
||||
mrrc p15, 0, r4, r5, c7 @ PAR
|
||||
mrc p15, 0, r6, c10, c3, 0 @ AMAIR0
|
||||
mrc p15, 0, r7, c10, c3, 1 @ AMAIR1
|
||||
|
||||
.if \store_to_vcpu == 0
|
||||
push {r2,r4-r5}
|
||||
push {r2,r4-r7}
|
||||
.else
|
||||
str r2, [vcpu, #CP15_OFFSET(c14_CNTKCTL)]
|
||||
add r12, vcpu, #CP15_OFFSET(c7_PAR)
|
||||
strd r4, r5, [r12]
|
||||
str r6, [vcpu, #CP15_OFFSET(c10_AMAIR0)]
|
||||
str r7, [vcpu, #CP15_OFFSET(c10_AMAIR1)]
|
||||
.endif
|
||||
.endm
|
||||
|
||||
|
|
@ -322,15 +327,19 @@ vcpu .req r0 @ vcpu pointer always in r0
|
|||
*/
|
||||
.macro write_cp15_state read_from_vcpu
|
||||
.if \read_from_vcpu == 0
|
||||
pop {r2,r4-r5}
|
||||
pop {r2,r4-r7}
|
||||
.else
|
||||
ldr r2, [vcpu, #CP15_OFFSET(c14_CNTKCTL)]
|
||||
add r12, vcpu, #CP15_OFFSET(c7_PAR)
|
||||
ldrd r4, r5, [r12]
|
||||
ldr r6, [vcpu, #CP15_OFFSET(c10_AMAIR0)]
|
||||
ldr r7, [vcpu, #CP15_OFFSET(c10_AMAIR1)]
|
||||
.endif
|
||||
|
||||
mcr p15, 0, r2, c14, c1, 0 @ CNTKCTL
|
||||
mcrr p15, 0, r4, r5, c7 @ PAR
|
||||
mcr p15, 0, r6, c10, c3, 0 @ AMAIR0
|
||||
mcr p15, 0, r7, c10, c3, 1 @ AMAIR1
|
||||
|
||||
.if \read_from_vcpu == 0
|
||||
pop {r2-r12}
|
||||
|
|
@ -412,15 +421,23 @@ vcpu .req r0 @ vcpu pointer always in r0
|
|||
ldr r8, [r2, #GICH_ELRSR0]
|
||||
ldr r9, [r2, #GICH_ELRSR1]
|
||||
ldr r10, [r2, #GICH_APR]
|
||||
ARM_BE8(rev r3, r3 )
|
||||
ARM_BE8(rev r4, r4 )
|
||||
ARM_BE8(rev r5, r5 )
|
||||
ARM_BE8(rev r6, r6 )
|
||||
ARM_BE8(rev r7, r7 )
|
||||
ARM_BE8(rev r8, r8 )
|
||||
ARM_BE8(rev r9, r9 )
|
||||
ARM_BE8(rev r10, r10 )
|
||||
|
||||
str r3, [r11, #VGIC_CPU_HCR]
|
||||
str r4, [r11, #VGIC_CPU_VMCR]
|
||||
str r5, [r11, #VGIC_CPU_MISR]
|
||||
str r6, [r11, #VGIC_CPU_EISR]
|
||||
str r7, [r11, #(VGIC_CPU_EISR + 4)]
|
||||
str r8, [r11, #VGIC_CPU_ELRSR]
|
||||
str r9, [r11, #(VGIC_CPU_ELRSR + 4)]
|
||||
str r10, [r11, #VGIC_CPU_APR]
|
||||
str r3, [r11, #VGIC_V2_CPU_HCR]
|
||||
str r4, [r11, #VGIC_V2_CPU_VMCR]
|
||||
str r5, [r11, #VGIC_V2_CPU_MISR]
|
||||
str r6, [r11, #VGIC_V2_CPU_EISR]
|
||||
str r7, [r11, #(VGIC_V2_CPU_EISR + 4)]
|
||||
str r8, [r11, #VGIC_V2_CPU_ELRSR]
|
||||
str r9, [r11, #(VGIC_V2_CPU_ELRSR + 4)]
|
||||
str r10, [r11, #VGIC_V2_CPU_APR]
|
||||
|
||||
/* Clear GICH_HCR */
|
||||
mov r5, #0
|
||||
|
|
@ -428,9 +445,10 @@ vcpu .req r0 @ vcpu pointer always in r0
|
|||
|
||||
/* Save list registers */
|
||||
add r2, r2, #GICH_LR0
|
||||
add r3, r11, #VGIC_CPU_LR
|
||||
add r3, r11, #VGIC_V2_CPU_LR
|
||||
ldr r4, [r11, #VGIC_CPU_NR_LR]
|
||||
1: ldr r6, [r2], #4
|
||||
ARM_BE8(rev r6, r6 )
|
||||
str r6, [r3], #4
|
||||
subs r4, r4, #1
|
||||
bne 1b
|
||||
|
|
@ -455,9 +473,12 @@ vcpu .req r0 @ vcpu pointer always in r0
|
|||
add r11, vcpu, #VCPU_VGIC_CPU
|
||||
|
||||
/* We only restore a minimal set of registers */
|
||||
ldr r3, [r11, #VGIC_CPU_HCR]
|
||||
ldr r4, [r11, #VGIC_CPU_VMCR]
|
||||
ldr r8, [r11, #VGIC_CPU_APR]
|
||||
ldr r3, [r11, #VGIC_V2_CPU_HCR]
|
||||
ldr r4, [r11, #VGIC_V2_CPU_VMCR]
|
||||
ldr r8, [r11, #VGIC_V2_CPU_APR]
|
||||
ARM_BE8(rev r3, r3 )
|
||||
ARM_BE8(rev r4, r4 )
|
||||
ARM_BE8(rev r8, r8 )
|
||||
|
||||
str r3, [r2, #GICH_HCR]
|
||||
str r4, [r2, #GICH_VMCR]
|
||||
|
|
@ -465,9 +486,10 @@ vcpu .req r0 @ vcpu pointer always in r0
|
|||
|
||||
/* Restore list registers */
|
||||
add r2, r2, #GICH_LR0
|
||||
add r3, r11, #VGIC_CPU_LR
|
||||
add r3, r11, #VGIC_V2_CPU_LR
|
||||
ldr r4, [r11, #VGIC_CPU_NR_LR]
|
||||
1: ldr r6, [r3], #4
|
||||
ARM_BE8(rev r6, r6 )
|
||||
str r6, [r2], #4
|
||||
subs r4, r4, #1
|
||||
bne 1b
|
||||
|
|
@ -498,7 +520,7 @@ vcpu .req r0 @ vcpu pointer always in r0
|
|||
mcr p15, 0, r2, c14, c3, 1 @ CNTV_CTL
|
||||
isb
|
||||
|
||||
mrrc p15, 3, r2, r3, c14 @ CNTV_CVAL
|
||||
mrrc p15, 3, rr_lo_hi(r2, r3), c14 @ CNTV_CVAL
|
||||
ldr r4, =VCPU_TIMER_CNTV_CVAL
|
||||
add r5, vcpu, r4
|
||||
strd r2, r3, [r5]
|
||||
|
|
@ -538,12 +560,12 @@ vcpu .req r0 @ vcpu pointer always in r0
|
|||
|
||||
ldr r2, [r4, #KVM_TIMER_CNTVOFF]
|
||||
ldr r3, [r4, #(KVM_TIMER_CNTVOFF + 4)]
|
||||
mcrr p15, 4, r2, r3, c14 @ CNTVOFF
|
||||
mcrr p15, 4, rr_lo_hi(r2, r3), c14 @ CNTVOFF
|
||||
|
||||
ldr r4, =VCPU_TIMER_CNTV_CVAL
|
||||
add r5, vcpu, r4
|
||||
ldrd r2, r3, [r5]
|
||||
mcrr p15, 3, r2, r3, c14 @ CNTV_CVAL
|
||||
mcrr p15, 3, rr_lo_hi(r2, r3), c14 @ CNTV_CVAL
|
||||
isb
|
||||
|
||||
ldr r2, [vcpu, #VCPU_TIMER_CNTV_CTL]
|
||||
|
|
@ -597,17 +619,14 @@ vcpu .req r0 @ vcpu pointer always in r0
|
|||
|
||||
/* Enable/Disable: stage-2 trans., trap interrupts, trap wfi, trap smc */
|
||||
.macro configure_hyp_role operation
|
||||
mrc p15, 4, r2, c1, c1, 0 @ HCR
|
||||
bic r2, r2, #HCR_VIRT_EXCP_MASK
|
||||
ldr r3, =HCR_GUEST_MASK
|
||||
.if \operation == vmentry
|
||||
orr r2, r2, r3
|
||||
ldr r2, [vcpu, #VCPU_HCR]
|
||||
ldr r3, [vcpu, #VCPU_IRQ_LINES]
|
||||
orr r2, r2, r3
|
||||
.else
|
||||
bic r2, r2, r3
|
||||
mov r2, #0
|
||||
.endif
|
||||
mcr p15, 4, r2, c1, c1, 0
|
||||
mcr p15, 4, r2, c1, c1, 0 @ HCR
|
||||
.endm
|
||||
|
||||
.macro load_vcpu
|
||||
|
|
|
|||
|
|
@ -23,6 +23,68 @@
|
|||
|
||||
#include "trace.h"
|
||||
|
||||
static void mmio_write_buf(char *buf, unsigned int len, unsigned long data)
|
||||
{
|
||||
void *datap = NULL;
|
||||
union {
|
||||
u8 byte;
|
||||
u16 hword;
|
||||
u32 word;
|
||||
u64 dword;
|
||||
} tmp;
|
||||
|
||||
switch (len) {
|
||||
case 1:
|
||||
tmp.byte = data;
|
||||
datap = &tmp.byte;
|
||||
break;
|
||||
case 2:
|
||||
tmp.hword = data;
|
||||
datap = &tmp.hword;
|
||||
break;
|
||||
case 4:
|
||||
tmp.word = data;
|
||||
datap = &tmp.word;
|
||||
break;
|
||||
case 8:
|
||||
tmp.dword = data;
|
||||
datap = &tmp.dword;
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(buf, datap, len);
|
||||
}
|
||||
|
||||
static unsigned long mmio_read_buf(char *buf, unsigned int len)
|
||||
{
|
||||
unsigned long data = 0;
|
||||
union {
|
||||
u16 hword;
|
||||
u32 word;
|
||||
u64 dword;
|
||||
} tmp;
|
||||
|
||||
switch (len) {
|
||||
case 1:
|
||||
data = buf[0];
|
||||
break;
|
||||
case 2:
|
||||
memcpy(&tmp.hword, buf, len);
|
||||
data = tmp.hword;
|
||||
break;
|
||||
case 4:
|
||||
memcpy(&tmp.word, buf, len);
|
||||
data = tmp.word;
|
||||
break;
|
||||
case 8:
|
||||
memcpy(&tmp.dword, buf, len);
|
||||
data = tmp.dword;
|
||||
break;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
|
||||
* @vcpu: The VCPU pointer
|
||||
|
|
@ -33,28 +95,27 @@
|
|||
*/
|
||||
int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
{
|
||||
unsigned long *dest;
|
||||
unsigned long data;
|
||||
unsigned int len;
|
||||
int mask;
|
||||
|
||||
if (!run->mmio.is_write) {
|
||||
dest = vcpu_reg(vcpu, vcpu->arch.mmio_decode.rt);
|
||||
*dest = 0;
|
||||
|
||||
len = run->mmio.len;
|
||||
if (len > sizeof(unsigned long))
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(dest, run->mmio.data, len);
|
||||
|
||||
trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr,
|
||||
*((u64 *)run->mmio.data));
|
||||
data = mmio_read_buf(run->mmio.data, len);
|
||||
|
||||
if (vcpu->arch.mmio_decode.sign_extend &&
|
||||
len < sizeof(unsigned long)) {
|
||||
mask = 1U << ((len * 8) - 1);
|
||||
*dest = (*dest ^ mask) - mask;
|
||||
data = (data ^ mask) - mask;
|
||||
}
|
||||
|
||||
trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr,
|
||||
data);
|
||||
data = vcpu_data_host_to_guest(vcpu, data, len);
|
||||
*vcpu_reg(vcpu, vcpu->arch.mmio_decode.rt) = data;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -63,7 +124,8 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||
static int decode_hsr(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
struct kvm_exit_mmio *mmio)
|
||||
{
|
||||
unsigned long rt, len;
|
||||
unsigned long rt;
|
||||
int len;
|
||||
bool is_write, sign_extend;
|
||||
|
||||
if (kvm_vcpu_dabt_isextabt(vcpu)) {
|
||||
|
|
@ -86,12 +148,6 @@ static int decode_hsr(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
|||
sign_extend = kvm_vcpu_dabt_issext(vcpu);
|
||||
rt = kvm_vcpu_dabt_get_rd(vcpu);
|
||||
|
||||
if (kvm_vcpu_reg_is_pc(vcpu, rt)) {
|
||||
/* IO memory trying to read/write pc */
|
||||
kvm_inject_pabt(vcpu, kvm_vcpu_get_hfar(vcpu));
|
||||
return 1;
|
||||
}
|
||||
|
||||
mmio->is_write = is_write;
|
||||
mmio->phys_addr = fault_ipa;
|
||||
mmio->len = len;
|
||||
|
|
@ -110,6 +166,7 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
|||
phys_addr_t fault_ipa)
|
||||
{
|
||||
struct kvm_exit_mmio mmio;
|
||||
unsigned long data;
|
||||
unsigned long rt;
|
||||
int ret;
|
||||
|
||||
|
|
@ -130,13 +187,15 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
|||
}
|
||||
|
||||
rt = vcpu->arch.mmio_decode.rt;
|
||||
data = vcpu_data_guest_to_host(vcpu, *vcpu_reg(vcpu, rt), mmio.len);
|
||||
|
||||
trace_kvm_mmio((mmio.is_write) ? KVM_TRACE_MMIO_WRITE :
|
||||
KVM_TRACE_MMIO_READ_UNSATISFIED,
|
||||
mmio.len, fault_ipa,
|
||||
(mmio.is_write) ? *vcpu_reg(vcpu, rt) : 0);
|
||||
(mmio.is_write) ? data : 0);
|
||||
|
||||
if (mmio.is_write)
|
||||
memcpy(mmio.data, vcpu_reg(vcpu, rt), mmio.len);
|
||||
mmio_write_buf(mmio.data, mmio.len, data);
|
||||
|
||||
if (vgic_handle_mmio(vcpu, run, &mmio))
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/mman.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/hugetlb.h>
|
||||
#include <trace/events/kvm.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
|
@ -41,6 +42,10 @@ static unsigned long hyp_idmap_start;
|
|||
static unsigned long hyp_idmap_end;
|
||||
static phys_addr_t hyp_idmap_vector;
|
||||
|
||||
#define pgd_order get_order(PTRS_PER_PGD * sizeof(pgd_t))
|
||||
|
||||
#define kvm_pmd_huge(_x) (pmd_huge(_x) || pmd_trans_huge(_x))
|
||||
|
||||
static void kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
|
||||
{
|
||||
/*
|
||||
|
|
@ -85,9 +90,19 @@ static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc)
|
|||
return p;
|
||||
}
|
||||
|
||||
static void clear_pgd_entry(struct kvm *kvm, pgd_t *pgd, phys_addr_t addr)
|
||||
{
|
||||
pud_t *pud_table __maybe_unused = pud_offset(pgd, 0);
|
||||
pgd_clear(pgd);
|
||||
kvm_tlb_flush_vmid_ipa(kvm, addr);
|
||||
pud_free(NULL, pud_table);
|
||||
put_page(virt_to_page(pgd));
|
||||
}
|
||||
|
||||
static void clear_pud_entry(struct kvm *kvm, pud_t *pud, phys_addr_t addr)
|
||||
{
|
||||
pmd_t *pmd_table = pmd_offset(pud, 0);
|
||||
VM_BUG_ON(pud_huge(*pud));
|
||||
pud_clear(pud);
|
||||
kvm_tlb_flush_vmid_ipa(kvm, addr);
|
||||
pmd_free(NULL, pmd_table);
|
||||
|
|
@ -97,73 +112,186 @@ static void clear_pud_entry(struct kvm *kvm, pud_t *pud, phys_addr_t addr)
|
|||
static void clear_pmd_entry(struct kvm *kvm, pmd_t *pmd, phys_addr_t addr)
|
||||
{
|
||||
pte_t *pte_table = pte_offset_kernel(pmd, 0);
|
||||
VM_BUG_ON(kvm_pmd_huge(*pmd));
|
||||
pmd_clear(pmd);
|
||||
kvm_tlb_flush_vmid_ipa(kvm, addr);
|
||||
pte_free_kernel(NULL, pte_table);
|
||||
put_page(virt_to_page(pmd));
|
||||
}
|
||||
|
||||
static bool pmd_empty(pmd_t *pmd)
|
||||
static void unmap_ptes(struct kvm *kvm, pmd_t *pmd,
|
||||
phys_addr_t addr, phys_addr_t end)
|
||||
{
|
||||
struct page *pmd_page = virt_to_page(pmd);
|
||||
return page_count(pmd_page) == 1;
|
||||
}
|
||||
phys_addr_t start_addr = addr;
|
||||
pte_t *pte, *start_pte;
|
||||
|
||||
static void clear_pte_entry(struct kvm *kvm, pte_t *pte, phys_addr_t addr)
|
||||
{
|
||||
if (pte_present(*pte)) {
|
||||
kvm_set_pte(pte, __pte(0));
|
||||
put_page(virt_to_page(pte));
|
||||
kvm_tlb_flush_vmid_ipa(kvm, addr);
|
||||
}
|
||||
}
|
||||
|
||||
static bool pte_empty(pte_t *pte)
|
||||
{
|
||||
struct page *pte_page = virt_to_page(pte);
|
||||
return page_count(pte_page) == 1;
|
||||
}
|
||||
|
||||
static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
|
||||
unsigned long long start, u64 size)
|
||||
{
|
||||
pgd_t *pgd;
|
||||
pud_t *pud;
|
||||
pmd_t *pmd;
|
||||
pte_t *pte;
|
||||
unsigned long long addr = start, end = start + size;
|
||||
u64 range;
|
||||
|
||||
while (addr < end) {
|
||||
pgd = pgdp + pgd_index(addr);
|
||||
pud = pud_offset(pgd, addr);
|
||||
if (pud_none(*pud)) {
|
||||
addr += PUD_SIZE;
|
||||
continue;
|
||||
start_pte = pte = pte_offset_kernel(pmd, addr);
|
||||
do {
|
||||
if (!pte_none(*pte)) {
|
||||
kvm_set_pte(pte, __pte(0));
|
||||
put_page(virt_to_page(pte));
|
||||
kvm_tlb_flush_vmid_ipa(kvm, addr);
|
||||
}
|
||||
} while (pte++, addr += PAGE_SIZE, addr != end);
|
||||
|
||||
pmd = pmd_offset(pud, addr);
|
||||
if (pmd_none(*pmd)) {
|
||||
addr += PMD_SIZE;
|
||||
continue;
|
||||
}
|
||||
if (kvm_pte_table_empty(start_pte))
|
||||
clear_pmd_entry(kvm, pmd, start_addr);
|
||||
}
|
||||
|
||||
pte = pte_offset_kernel(pmd, addr);
|
||||
clear_pte_entry(kvm, pte, addr);
|
||||
range = PAGE_SIZE;
|
||||
static void unmap_pmds(struct kvm *kvm, pud_t *pud,
|
||||
phys_addr_t addr, phys_addr_t end)
|
||||
{
|
||||
phys_addr_t next, start_addr = addr;
|
||||
pmd_t *pmd, *start_pmd;
|
||||
|
||||
/* If we emptied the pte, walk back up the ladder */
|
||||
if (pte_empty(pte)) {
|
||||
clear_pmd_entry(kvm, pmd, addr);
|
||||
range = PMD_SIZE;
|
||||
if (pmd_empty(pmd)) {
|
||||
clear_pud_entry(kvm, pud, addr);
|
||||
range = PUD_SIZE;
|
||||
start_pmd = pmd = pmd_offset(pud, addr);
|
||||
do {
|
||||
next = kvm_pmd_addr_end(addr, end);
|
||||
if (!pmd_none(*pmd)) {
|
||||
if (kvm_pmd_huge(*pmd)) {
|
||||
pmd_clear(pmd);
|
||||
kvm_tlb_flush_vmid_ipa(kvm, addr);
|
||||
put_page(virt_to_page(pmd));
|
||||
} else {
|
||||
unmap_ptes(kvm, pmd, addr, next);
|
||||
}
|
||||
}
|
||||
} while (pmd++, addr = next, addr != end);
|
||||
|
||||
addr += range;
|
||||
}
|
||||
if (kvm_pmd_table_empty(start_pmd))
|
||||
clear_pud_entry(kvm, pud, start_addr);
|
||||
}
|
||||
|
||||
static void unmap_puds(struct kvm *kvm, pgd_t *pgd,
|
||||
phys_addr_t addr, phys_addr_t end)
|
||||
{
|
||||
phys_addr_t next, start_addr = addr;
|
||||
pud_t *pud, *start_pud;
|
||||
|
||||
start_pud = pud = pud_offset(pgd, addr);
|
||||
do {
|
||||
next = kvm_pud_addr_end(addr, end);
|
||||
if (!pud_none(*pud)) {
|
||||
if (pud_huge(*pud)) {
|
||||
pud_clear(pud);
|
||||
kvm_tlb_flush_vmid_ipa(kvm, addr);
|
||||
put_page(virt_to_page(pud));
|
||||
} else {
|
||||
unmap_pmds(kvm, pud, addr, next);
|
||||
}
|
||||
}
|
||||
} while (pud++, addr = next, addr != end);
|
||||
|
||||
if (kvm_pud_table_empty(start_pud))
|
||||
clear_pgd_entry(kvm, pgd, start_addr);
|
||||
}
|
||||
|
||||
|
||||
static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
|
||||
phys_addr_t start, u64 size)
|
||||
{
|
||||
pgd_t *pgd;
|
||||
phys_addr_t addr = start, end = start + size;
|
||||
phys_addr_t next;
|
||||
|
||||
pgd = pgdp + pgd_index(addr);
|
||||
do {
|
||||
next = kvm_pgd_addr_end(addr, end);
|
||||
unmap_puds(kvm, pgd, addr, next);
|
||||
} while (pgd++, addr = next, addr != end);
|
||||
}
|
||||
|
||||
static void stage2_flush_ptes(struct kvm *kvm, pmd_t *pmd,
|
||||
phys_addr_t addr, phys_addr_t end)
|
||||
{
|
||||
pte_t *pte;
|
||||
|
||||
pte = pte_offset_kernel(pmd, addr);
|
||||
do {
|
||||
if (!pte_none(*pte)) {
|
||||
hva_t hva = gfn_to_hva(kvm, addr >> PAGE_SHIFT);
|
||||
kvm_flush_dcache_to_poc((void*)hva, PAGE_SIZE);
|
||||
}
|
||||
} while (pte++, addr += PAGE_SIZE, addr != end);
|
||||
}
|
||||
|
||||
static void stage2_flush_pmds(struct kvm *kvm, pud_t *pud,
|
||||
phys_addr_t addr, phys_addr_t end)
|
||||
{
|
||||
pmd_t *pmd;
|
||||
phys_addr_t next;
|
||||
|
||||
pmd = pmd_offset(pud, addr);
|
||||
do {
|
||||
next = kvm_pmd_addr_end(addr, end);
|
||||
if (!pmd_none(*pmd)) {
|
||||
if (kvm_pmd_huge(*pmd)) {
|
||||
hva_t hva = gfn_to_hva(kvm, addr >> PAGE_SHIFT);
|
||||
kvm_flush_dcache_to_poc((void*)hva, PMD_SIZE);
|
||||
} else {
|
||||
stage2_flush_ptes(kvm, pmd, addr, next);
|
||||
}
|
||||
}
|
||||
} while (pmd++, addr = next, addr != end);
|
||||
}
|
||||
|
||||
static void stage2_flush_puds(struct kvm *kvm, pgd_t *pgd,
|
||||
phys_addr_t addr, phys_addr_t end)
|
||||
{
|
||||
pud_t *pud;
|
||||
phys_addr_t next;
|
||||
|
||||
pud = pud_offset(pgd, addr);
|
||||
do {
|
||||
next = kvm_pud_addr_end(addr, end);
|
||||
if (!pud_none(*pud)) {
|
||||
if (pud_huge(*pud)) {
|
||||
hva_t hva = gfn_to_hva(kvm, addr >> PAGE_SHIFT);
|
||||
kvm_flush_dcache_to_poc((void*)hva, PUD_SIZE);
|
||||
} else {
|
||||
stage2_flush_pmds(kvm, pud, addr, next);
|
||||
}
|
||||
}
|
||||
} while (pud++, addr = next, addr != end);
|
||||
}
|
||||
|
||||
static void stage2_flush_memslot(struct kvm *kvm,
|
||||
struct kvm_memory_slot *memslot)
|
||||
{
|
||||
phys_addr_t addr = memslot->base_gfn << PAGE_SHIFT;
|
||||
phys_addr_t end = addr + PAGE_SIZE * memslot->npages;
|
||||
phys_addr_t next;
|
||||
pgd_t *pgd;
|
||||
|
||||
pgd = kvm->arch.pgd + pgd_index(addr);
|
||||
do {
|
||||
next = kvm_pgd_addr_end(addr, end);
|
||||
stage2_flush_puds(kvm, pgd, addr, next);
|
||||
} while (pgd++, addr = next, addr != end);
|
||||
}
|
||||
|
||||
/**
|
||||
* stage2_flush_vm - Invalidate cache for pages mapped in stage 2
|
||||
* @kvm: The struct kvm pointer
|
||||
*
|
||||
* Go through the stage 2 page tables and invalidate any cache lines
|
||||
* backing memory already mapped to the VM.
|
||||
*/
|
||||
void stage2_flush_vm(struct kvm *kvm)
|
||||
{
|
||||
struct kvm_memslots *slots;
|
||||
struct kvm_memory_slot *memslot;
|
||||
int idx;
|
||||
|
||||
idx = srcu_read_lock(&kvm->srcu);
|
||||
spin_lock(&kvm->mmu_lock);
|
||||
|
||||
slots = kvm_memslots(kvm);
|
||||
kvm_for_each_memslot(memslot, slots)
|
||||
stage2_flush_memslot(kvm, memslot);
|
||||
|
||||
spin_unlock(&kvm->mmu_lock);
|
||||
srcu_read_unlock(&kvm->srcu, idx);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -178,14 +306,14 @@ void free_boot_hyp_pgd(void)
|
|||
if (boot_hyp_pgd) {
|
||||
unmap_range(NULL, boot_hyp_pgd, hyp_idmap_start, PAGE_SIZE);
|
||||
unmap_range(NULL, boot_hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE);
|
||||
kfree(boot_hyp_pgd);
|
||||
free_pages((unsigned long)boot_hyp_pgd, pgd_order);
|
||||
boot_hyp_pgd = NULL;
|
||||
}
|
||||
|
||||
if (hyp_pgd)
|
||||
unmap_range(NULL, hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE);
|
||||
|
||||
kfree(init_bounce_page);
|
||||
free_page((unsigned long)init_bounce_page);
|
||||
init_bounce_page = NULL;
|
||||
|
||||
mutex_unlock(&kvm_hyp_pgd_mutex);
|
||||
|
|
@ -215,7 +343,7 @@ void free_hyp_pgds(void)
|
|||
for (addr = VMALLOC_START; is_vmalloc_addr((void*)addr); addr += PGDIR_SIZE)
|
||||
unmap_range(NULL, hyp_pgd, KERN_TO_HYP(addr), PGDIR_SIZE);
|
||||
|
||||
kfree(hyp_pgd);
|
||||
free_pages((unsigned long)hyp_pgd, pgd_order);
|
||||
hyp_pgd = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -404,9 +532,6 @@ int kvm_alloc_stage2_pgd(struct kvm *kvm)
|
|||
if (!pgd)
|
||||
return -ENOMEM;
|
||||
|
||||
/* stage-2 pgd must be aligned to its size */
|
||||
VM_BUG_ON((unsigned long)pgd & (S2_PGD_SIZE - 1));
|
||||
|
||||
memset(pgd, 0, PTRS_PER_S2_PGD * sizeof(pgd_t));
|
||||
kvm_clean_pgd(pgd);
|
||||
kvm->arch.pgd = pgd;
|
||||
|
|
@ -451,29 +576,71 @@ void kvm_free_stage2_pgd(struct kvm *kvm)
|
|||
kvm->arch.pgd = NULL;
|
||||
}
|
||||
|
||||
|
||||
static int stage2_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
|
||||
phys_addr_t addr, const pte_t *new_pte, bool iomap)
|
||||
static pmd_t *stage2_get_pmd(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
|
||||
phys_addr_t addr)
|
||||
{
|
||||
pgd_t *pgd;
|
||||
pud_t *pud;
|
||||
pmd_t *pmd;
|
||||
pte_t *pte, old_pte;
|
||||
|
||||
/* Create 2nd stage page table mapping - Level 1 */
|
||||
pgd = kvm->arch.pgd + pgd_index(addr);
|
||||
pud = pud_offset(pgd, addr);
|
||||
if (pud_none(*pud)) {
|
||||
if (!cache)
|
||||
return 0; /* ignore calls from kvm_set_spte_hva */
|
||||
return NULL;
|
||||
pmd = mmu_memory_cache_alloc(cache);
|
||||
pud_populate(NULL, pud, pmd);
|
||||
get_page(virt_to_page(pud));
|
||||
}
|
||||
|
||||
pmd = pmd_offset(pud, addr);
|
||||
return pmd_offset(pud, addr);
|
||||
}
|
||||
|
||||
/* Create 2nd stage page table mapping - Level 2 */
|
||||
static int stage2_set_pmd_huge(struct kvm *kvm, struct kvm_mmu_memory_cache
|
||||
*cache, phys_addr_t addr, const pmd_t *new_pmd)
|
||||
{
|
||||
pmd_t *pmd, old_pmd;
|
||||
|
||||
pmd = stage2_get_pmd(kvm, cache, addr);
|
||||
VM_BUG_ON(!pmd);
|
||||
|
||||
/*
|
||||
* Mapping in huge pages should only happen through a fault. If a
|
||||
* page is merged into a transparent huge page, the individual
|
||||
* subpages of that huge page should be unmapped through MMU
|
||||
* notifiers before we get here.
|
||||
*
|
||||
* Merging of CompoundPages is not supported; they should become
|
||||
* splitting first, unmapped, merged, and mapped back in on-demand.
|
||||
*/
|
||||
VM_BUG_ON(pmd_present(*pmd) && pmd_pfn(*pmd) != pmd_pfn(*new_pmd));
|
||||
|
||||
old_pmd = *pmd;
|
||||
kvm_set_pmd(pmd, *new_pmd);
|
||||
if (pmd_present(old_pmd))
|
||||
kvm_tlb_flush_vmid_ipa(kvm, addr);
|
||||
else
|
||||
get_page(virt_to_page(pmd));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stage2_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
|
||||
phys_addr_t addr, const pte_t *new_pte, bool iomap)
|
||||
{
|
||||
pmd_t *pmd;
|
||||
pte_t *pte, old_pte;
|
||||
|
||||
/* Create stage-2 page table mapping - Level 1 */
|
||||
pmd = stage2_get_pmd(kvm, cache, addr);
|
||||
if (!pmd) {
|
||||
/*
|
||||
* Ignore calls from kvm_set_spte_hva for unallocated
|
||||
* address ranges.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create stage-2 page mappings - Level 2 */
|
||||
if (pmd_none(*pmd)) {
|
||||
if (!cache)
|
||||
return 0; /* ignore calls from kvm_set_spte_hva */
|
||||
|
|
@ -520,7 +687,6 @@ int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
|
|||
|
||||
for (addr = guest_ipa; addr < end; addr += PAGE_SIZE) {
|
||||
pte_t pte = pfn_pte(pfn, PAGE_S2_DEVICE);
|
||||
kvm_set_s2pte_writable(&pte);
|
||||
|
||||
ret = mmu_topup_memory_cache(&cache, 2, 2);
|
||||
if (ret)
|
||||
|
|
@ -539,23 +705,97 @@ int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool transparent_hugepage_adjust(pfn_t *pfnp, phys_addr_t *ipap)
|
||||
{
|
||||
pfn_t pfn = *pfnp;
|
||||
gfn_t gfn = *ipap >> PAGE_SHIFT;
|
||||
|
||||
if (PageTransCompound(pfn_to_page(pfn))) {
|
||||
unsigned long mask;
|
||||
/*
|
||||
* The address we faulted on is backed by a transparent huge
|
||||
* page. However, because we map the compound huge page and
|
||||
* not the individual tail page, we need to transfer the
|
||||
* refcount to the head page. We have to be careful that the
|
||||
* THP doesn't start to split while we are adjusting the
|
||||
* refcounts.
|
||||
*
|
||||
* We are sure this doesn't happen, because mmu_notifier_retry
|
||||
* was successful and we are holding the mmu_lock, so if this
|
||||
* THP is trying to split, it will be blocked in the mmu
|
||||
* notifier before touching any of the pages, specifically
|
||||
* before being able to call __split_huge_page_refcount().
|
||||
*
|
||||
* We can therefore safely transfer the refcount from PG_tail
|
||||
* to PG_head and switch the pfn from a tail page to the head
|
||||
* page accordingly.
|
||||
*/
|
||||
mask = PTRS_PER_PMD - 1;
|
||||
VM_BUG_ON((gfn & mask) != (pfn & mask));
|
||||
if (pfn & mask) {
|
||||
*ipap &= PMD_MASK;
|
||||
kvm_release_pfn_clean(pfn);
|
||||
pfn &= ~mask;
|
||||
kvm_get_pfn(pfn);
|
||||
*pfnp = pfn;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static 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 int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
gfn_t gfn, struct kvm_memory_slot *memslot,
|
||||
struct kvm_memory_slot *memslot, unsigned long hva,
|
||||
unsigned long fault_status)
|
||||
{
|
||||
pte_t new_pte;
|
||||
pfn_t pfn;
|
||||
int ret;
|
||||
bool write_fault, writable;
|
||||
bool write_fault, writable, hugetlb = false, force_pte = false;
|
||||
unsigned long mmu_seq;
|
||||
gfn_t gfn = fault_ipa >> PAGE_SHIFT;
|
||||
struct kvm *kvm = vcpu->kvm;
|
||||
struct kvm_mmu_memory_cache *memcache = &vcpu->arch.mmu_page_cache;
|
||||
struct vm_area_struct *vma;
|
||||
pfn_t pfn;
|
||||
pgprot_t mem_type = PAGE_S2;
|
||||
|
||||
write_fault = kvm_is_write_fault(kvm_vcpu_get_hsr(vcpu));
|
||||
write_fault = kvm_is_write_fault(vcpu);
|
||||
if (fault_status == FSC_PERM && !write_fault) {
|
||||
kvm_err("Unexpected L2 read permission error\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* Let's check if we will get back a huge page backed by hugetlbfs */
|
||||
down_read(¤t->mm->mmap_sem);
|
||||
vma = find_vma_intersection(current->mm, hva, hva + 1);
|
||||
if (is_vm_hugetlb_page(vma)) {
|
||||
hugetlb = true;
|
||||
gfn = (fault_ipa & PMD_MASK) >> PAGE_SHIFT;
|
||||
} else {
|
||||
/*
|
||||
* Pages belonging to memslots that don't have the same
|
||||
* alignment for userspace and IPA cannot be mapped using
|
||||
* block descriptors even if the pages belong to a THP for
|
||||
* the process, because the stage-2 block descriptor will
|
||||
* cover more than a single THP and we loose atomicity for
|
||||
* unmapping, updates, and splits of the THP or other pages
|
||||
* in the stage-2 block range.
|
||||
*/
|
||||
if ((memslot->userspace_addr & ~PMD_MASK) !=
|
||||
((memslot->base_gfn << PAGE_SHIFT) & ~PMD_MASK))
|
||||
force_pte = true;
|
||||
}
|
||||
up_read(¤t->mm->mmap_sem);
|
||||
|
||||
/* We need minimum second+third level pages */
|
||||
ret = mmu_topup_memory_cache(memcache, 2, KVM_NR_MEM_OBJS);
|
||||
if (ret)
|
||||
|
|
@ -573,26 +813,44 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
|||
*/
|
||||
smp_rmb();
|
||||
|
||||
pfn = gfn_to_pfn_prot(vcpu->kvm, gfn, write_fault, &writable);
|
||||
pfn = gfn_to_pfn_prot(kvm, gfn, write_fault, &writable);
|
||||
if (is_error_pfn(pfn))
|
||||
return -EFAULT;
|
||||
|
||||
new_pte = pfn_pte(pfn, PAGE_S2);
|
||||
coherent_icache_guest_page(vcpu->kvm, gfn);
|
||||
if (kvm_is_mmio_pfn(pfn))
|
||||
mem_type = PAGE_S2_DEVICE;
|
||||
|
||||
spin_lock(&vcpu->kvm->mmu_lock);
|
||||
if (mmu_notifier_retry(vcpu->kvm, mmu_seq))
|
||||
spin_lock(&kvm->mmu_lock);
|
||||
if (mmu_notifier_retry(kvm, mmu_seq))
|
||||
goto out_unlock;
|
||||
if (writable) {
|
||||
kvm_set_s2pte_writable(&new_pte);
|
||||
kvm_set_pfn_dirty(pfn);
|
||||
if (!hugetlb && !force_pte)
|
||||
hugetlb = transparent_hugepage_adjust(&pfn, &fault_ipa);
|
||||
|
||||
if (hugetlb) {
|
||||
pmd_t new_pmd = pfn_pmd(pfn, mem_type);
|
||||
new_pmd = pmd_mkhuge(new_pmd);
|
||||
if (writable) {
|
||||
kvm_set_s2pmd_writable(&new_pmd);
|
||||
kvm_set_pfn_dirty(pfn);
|
||||
}
|
||||
coherent_cache_guest_page(vcpu, hva & PMD_MASK, PMD_SIZE);
|
||||
ret = stage2_set_pmd_huge(kvm, memcache, fault_ipa, &new_pmd);
|
||||
} else {
|
||||
pte_t new_pte = pfn_pte(pfn, mem_type);
|
||||
if (writable) {
|
||||
kvm_set_s2pte_writable(&new_pte);
|
||||
kvm_set_pfn_dirty(pfn);
|
||||
}
|
||||
coherent_cache_guest_page(vcpu, hva, PAGE_SIZE);
|
||||
ret = stage2_set_pte(kvm, memcache, fault_ipa, &new_pte,
|
||||
mem_type == PAGE_S2_DEVICE);
|
||||
}
|
||||
stage2_set_pte(vcpu->kvm, memcache, fault_ipa, &new_pte, false);
|
||||
|
||||
|
||||
out_unlock:
|
||||
spin_unlock(&vcpu->kvm->mmu_lock);
|
||||
spin_unlock(&kvm->mmu_lock);
|
||||
kvm_release_pfn_clean(pfn);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -612,7 +870,8 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||
unsigned long fault_status;
|
||||
phys_addr_t fault_ipa;
|
||||
struct kvm_memory_slot *memslot;
|
||||
bool is_iabt;
|
||||
unsigned long hva;
|
||||
bool is_iabt, write_fault, writable;
|
||||
gfn_t gfn;
|
||||
int ret, idx;
|
||||
|
||||
|
|
@ -623,17 +882,22 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||
kvm_vcpu_get_hfar(vcpu), fault_ipa);
|
||||
|
||||
/* Check the stage-2 fault is trans. fault or write fault */
|
||||
fault_status = kvm_vcpu_trap_get_fault(vcpu);
|
||||
fault_status = kvm_vcpu_trap_get_fault_type(vcpu);
|
||||
if (fault_status != FSC_FAULT && fault_status != FSC_PERM) {
|
||||
kvm_err("Unsupported fault status: EC=%#x DFCS=%#lx\n",
|
||||
kvm_vcpu_trap_get_class(vcpu), fault_status);
|
||||
kvm_err("Unsupported FSC: EC=%#x xFSC=%#lx ESR_EL2=%#lx\n",
|
||||
kvm_vcpu_trap_get_class(vcpu),
|
||||
(unsigned long)kvm_vcpu_trap_get_fault(vcpu),
|
||||
(unsigned long)kvm_vcpu_get_hsr(vcpu));
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
idx = srcu_read_lock(&vcpu->kvm->srcu);
|
||||
|
||||
gfn = fault_ipa >> PAGE_SHIFT;
|
||||
if (!kvm_is_visible_gfn(vcpu->kvm, gfn)) {
|
||||
memslot = gfn_to_memslot(vcpu->kvm, gfn);
|
||||
hva = gfn_to_hva_memslot_prot(memslot, gfn, &writable);
|
||||
write_fault = kvm_is_write_fault(vcpu);
|
||||
if (kvm_is_error_hva(hva) || (write_fault && !writable)) {
|
||||
if (is_iabt) {
|
||||
/* Prefetch Abort on I/O address */
|
||||
kvm_inject_pabt(vcpu, kvm_vcpu_get_hfar(vcpu));
|
||||
|
|
@ -641,13 +905,6 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (fault_status != FSC_FAULT) {
|
||||
kvm_err("Unsupported fault status on io memory: %#lx\n",
|
||||
fault_status);
|
||||
ret = -EFAULT;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* The IPA is reported as [MAX:12], so we need to
|
||||
* complement it with the bottom 12 bits from the
|
||||
|
|
@ -659,9 +916,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||
goto out_unlock;
|
||||
}
|
||||
|
||||
memslot = gfn_to_memslot(vcpu->kvm, gfn);
|
||||
|
||||
ret = user_mem_abort(vcpu, fault_ipa, gfn, memslot, fault_status);
|
||||
ret = user_mem_abort(vcpu, fault_ipa, memslot, hva, fault_status);
|
||||
if (ret == 0)
|
||||
ret = 1;
|
||||
out_unlock:
|
||||
|
|
@ -779,9 +1034,9 @@ int kvm_mmu_init(void)
|
|||
{
|
||||
int err;
|
||||
|
||||
hyp_idmap_start = virt_to_phys(__hyp_idmap_text_start);
|
||||
hyp_idmap_end = virt_to_phys(__hyp_idmap_text_end);
|
||||
hyp_idmap_vector = virt_to_phys(__kvm_hyp_init);
|
||||
hyp_idmap_start = kvm_virt_to_phys(__hyp_idmap_text_start);
|
||||
hyp_idmap_end = kvm_virt_to_phys(__hyp_idmap_text_end);
|
||||
hyp_idmap_vector = kvm_virt_to_phys(__kvm_hyp_init);
|
||||
|
||||
if ((hyp_idmap_start ^ hyp_idmap_end) & PAGE_MASK) {
|
||||
/*
|
||||
|
|
@ -791,7 +1046,7 @@ int kvm_mmu_init(void)
|
|||
size_t len = __hyp_idmap_text_end - __hyp_idmap_text_start;
|
||||
phys_addr_t phys_base;
|
||||
|
||||
init_bounce_page = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
init_bounce_page = (void *)__get_free_page(GFP_KERNEL);
|
||||
if (!init_bounce_page) {
|
||||
kvm_err("Couldn't allocate HYP init bounce page\n");
|
||||
err = -ENOMEM;
|
||||
|
|
@ -808,7 +1063,7 @@ int kvm_mmu_init(void)
|
|||
*/
|
||||
kvm_flush_dcache_to_poc(init_bounce_page, len);
|
||||
|
||||
phys_base = virt_to_phys(init_bounce_page);
|
||||
phys_base = kvm_virt_to_phys(init_bounce_page);
|
||||
hyp_idmap_vector += phys_base - hyp_idmap_start;
|
||||
hyp_idmap_start = phys_base;
|
||||
hyp_idmap_end = phys_base + len;
|
||||
|
|
@ -817,8 +1072,9 @@ int kvm_mmu_init(void)
|
|||
(unsigned long)phys_base);
|
||||
}
|
||||
|
||||
hyp_pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL);
|
||||
boot_hyp_pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL);
|
||||
hyp_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, pgd_order);
|
||||
boot_hyp_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, pgd_order);
|
||||
|
||||
if (!hyp_pgd || !boot_hyp_pgd) {
|
||||
kvm_err("Hyp mode PGD not allocated\n");
|
||||
err = -ENOMEM;
|
||||
|
|
@ -864,3 +1120,49 @@ int kvm_mmu_init(void)
|
|||
free_hyp_pgds();
|
||||
return err;
|
||||
}
|
||||
|
||||
void kvm_arch_commit_memory_region(struct kvm *kvm,
|
||||
struct kvm_userspace_memory_region *mem,
|
||||
const struct kvm_memory_slot *old,
|
||||
enum kvm_mr_change change)
|
||||
{
|
||||
gpa_t gpa = old->base_gfn << PAGE_SHIFT;
|
||||
phys_addr_t size = old->npages << PAGE_SHIFT;
|
||||
if (change == KVM_MR_DELETE || change == KVM_MR_MOVE) {
|
||||
spin_lock(&kvm->mmu_lock);
|
||||
unmap_stage2_range(kvm, gpa, size);
|
||||
spin_unlock(&kvm->mmu_lock);
|
||||
}
|
||||
}
|
||||
|
||||
int kvm_arch_prepare_memory_region(struct kvm *kvm,
|
||||
struct kvm_memory_slot *memslot,
|
||||
struct kvm_userspace_memory_region *mem,
|
||||
enum kvm_mr_change change)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *free,
|
||||
struct kvm_memory_slot *dont)
|
||||
{
|
||||
}
|
||||
|
||||
int kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot,
|
||||
unsigned long npages)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kvm_arch_memslots_updated(struct kvm *kvm)
|
||||
{
|
||||
}
|
||||
|
||||
void kvm_arch_flush_shadow_all(struct kvm *kvm)
|
||||
{
|
||||
}
|
||||
|
||||
void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
|
||||
struct kvm_memory_slot *slot)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/kvm_host.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <asm/kvm_psci.h>
|
||||
|
||||
|
|
@ -26,6 +27,36 @@
|
|||
* as described in ARM document number ARM DEN 0022A.
|
||||
*/
|
||||
|
||||
#define AFFINITY_MASK(level) ~((0x1UL << ((level) * MPIDR_LEVEL_BITS)) - 1)
|
||||
|
||||
static unsigned long psci_affinity_mask(unsigned long affinity_level)
|
||||
{
|
||||
if (affinity_level <= 3)
|
||||
return MPIDR_HWID_BITMASK & AFFINITY_MASK(affinity_level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long kvm_psci_vcpu_suspend(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/*
|
||||
* NOTE: For simplicity, we make VCPU suspend emulation to be
|
||||
* same-as WFI (Wait-for-interrupt) emulation.
|
||||
*
|
||||
* This means for KVM the wakeup events are interrupts and
|
||||
* this is consistent with intended use of StateID as described
|
||||
* in section 5.4.1 of PSCI v0.2 specification (ARM DEN 0022A).
|
||||
*
|
||||
* Further, we also treat power-down request to be same as
|
||||
* stand-by request as-per section 5.4.2 clause 3 of PSCI v0.2
|
||||
* specification (ARM DEN 0022A). This means all suspend states
|
||||
* for KVM will preserve the register state.
|
||||
*/
|
||||
kvm_vcpu_block(vcpu);
|
||||
|
||||
return PSCI_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static void kvm_psci_vcpu_off(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
vcpu->arch.pause = true;
|
||||
|
|
@ -34,25 +65,41 @@ static void kvm_psci_vcpu_off(struct kvm_vcpu *vcpu)
|
|||
static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
|
||||
{
|
||||
struct kvm *kvm = source_vcpu->kvm;
|
||||
struct kvm_vcpu *vcpu;
|
||||
struct kvm_vcpu *vcpu = NULL, *tmp;
|
||||
wait_queue_head_t *wq;
|
||||
unsigned long cpu_id;
|
||||
unsigned long context_id;
|
||||
unsigned long mpidr;
|
||||
phys_addr_t target_pc;
|
||||
int i;
|
||||
|
||||
cpu_id = *vcpu_reg(source_vcpu, 1);
|
||||
if (vcpu_mode_is_32bit(source_vcpu))
|
||||
cpu_id &= ~((u32) 0);
|
||||
|
||||
if (cpu_id >= atomic_read(&kvm->online_vcpus))
|
||||
return KVM_PSCI_RET_INVAL;
|
||||
kvm_for_each_vcpu(i, tmp, kvm) {
|
||||
mpidr = kvm_vcpu_get_mpidr(tmp);
|
||||
if ((mpidr & MPIDR_HWID_BITMASK) == (cpu_id & MPIDR_HWID_BITMASK)) {
|
||||
vcpu = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure the caller requested a valid CPU and that the CPU is
|
||||
* turned off.
|
||||
*/
|
||||
if (!vcpu)
|
||||
return PSCI_RET_INVALID_PARAMS;
|
||||
if (!vcpu->arch.pause) {
|
||||
if (kvm_psci_version(source_vcpu) != KVM_ARM_PSCI_0_1)
|
||||
return PSCI_RET_ALREADY_ON;
|
||||
else
|
||||
return PSCI_RET_INVALID_PARAMS;
|
||||
}
|
||||
|
||||
target_pc = *vcpu_reg(source_vcpu, 2);
|
||||
|
||||
vcpu = kvm_get_vcpu(kvm, cpu_id);
|
||||
|
||||
wq = kvm_arch_vcpu_wq(vcpu);
|
||||
if (!waitqueue_active(wq))
|
||||
return KVM_PSCI_RET_INVAL;
|
||||
context_id = *vcpu_reg(source_vcpu, 3);
|
||||
|
||||
kvm_reset_vcpu(vcpu);
|
||||
|
||||
|
|
@ -62,26 +109,165 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
|
|||
vcpu_set_thumb(vcpu);
|
||||
}
|
||||
|
||||
/* Propagate caller endianness */
|
||||
if (kvm_vcpu_is_be(source_vcpu))
|
||||
kvm_vcpu_set_be(vcpu);
|
||||
|
||||
*vcpu_pc(vcpu) = target_pc;
|
||||
/*
|
||||
* NOTE: We always update r0 (or x0) because for PSCI v0.1
|
||||
* the general puspose registers are undefined upon CPU_ON.
|
||||
*/
|
||||
*vcpu_reg(vcpu, 0) = context_id;
|
||||
vcpu->arch.pause = false;
|
||||
smp_mb(); /* Make sure the above is visible */
|
||||
|
||||
wq = kvm_arch_vcpu_wq(vcpu);
|
||||
wake_up_interruptible(wq);
|
||||
|
||||
return KVM_PSCI_RET_SUCCESS;
|
||||
return PSCI_RET_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_psci_call - handle PSCI call if r0 value is in range
|
||||
* @vcpu: Pointer to the VCPU struct
|
||||
*
|
||||
* Handle PSCI calls from guests through traps from HVC or SMC instructions.
|
||||
* The calling convention is similar to SMC calls to the secure world where
|
||||
* the function number is placed in r0 and this function returns true if the
|
||||
* function number specified in r0 is withing the PSCI range, and false
|
||||
* otherwise.
|
||||
*/
|
||||
bool kvm_psci_call(struct kvm_vcpu *vcpu)
|
||||
static unsigned long kvm_psci_vcpu_affinity_info(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int i;
|
||||
unsigned long mpidr;
|
||||
unsigned long target_affinity;
|
||||
unsigned long target_affinity_mask;
|
||||
unsigned long lowest_affinity_level;
|
||||
struct kvm *kvm = vcpu->kvm;
|
||||
struct kvm_vcpu *tmp;
|
||||
|
||||
target_affinity = *vcpu_reg(vcpu, 1);
|
||||
lowest_affinity_level = *vcpu_reg(vcpu, 2);
|
||||
|
||||
/* Determine target affinity mask */
|
||||
target_affinity_mask = psci_affinity_mask(lowest_affinity_level);
|
||||
if (!target_affinity_mask)
|
||||
return PSCI_RET_INVALID_PARAMS;
|
||||
|
||||
/* Ignore other bits of target affinity */
|
||||
target_affinity &= target_affinity_mask;
|
||||
|
||||
/*
|
||||
* If one or more VCPU matching target affinity are running
|
||||
* then ON else OFF
|
||||
*/
|
||||
kvm_for_each_vcpu(i, tmp, kvm) {
|
||||
mpidr = kvm_vcpu_get_mpidr(tmp);
|
||||
if (((mpidr & target_affinity_mask) == target_affinity) &&
|
||||
!tmp->arch.pause) {
|
||||
return PSCI_0_2_AFFINITY_LEVEL_ON;
|
||||
}
|
||||
}
|
||||
|
||||
return PSCI_0_2_AFFINITY_LEVEL_OFF;
|
||||
}
|
||||
|
||||
static void kvm_prepare_system_event(struct kvm_vcpu *vcpu, u32 type)
|
||||
{
|
||||
memset(&vcpu->run->system_event, 0, sizeof(vcpu->run->system_event));
|
||||
vcpu->run->system_event.type = type;
|
||||
vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
|
||||
}
|
||||
|
||||
static void kvm_psci_system_off(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_SHUTDOWN);
|
||||
}
|
||||
|
||||
static void kvm_psci_system_reset(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_RESET);
|
||||
}
|
||||
|
||||
int kvm_psci_version(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
|
||||
return KVM_ARM_PSCI_0_2;
|
||||
|
||||
return KVM_ARM_PSCI_0_1;
|
||||
}
|
||||
|
||||
static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int ret = 1;
|
||||
unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0);
|
||||
unsigned long val;
|
||||
|
||||
switch (psci_fn) {
|
||||
case PSCI_0_2_FN_PSCI_VERSION:
|
||||
/*
|
||||
* Bits[31:16] = Major Version = 0
|
||||
* Bits[15:0] = Minor Version = 2
|
||||
*/
|
||||
val = 2;
|
||||
break;
|
||||
case PSCI_0_2_FN_CPU_SUSPEND:
|
||||
case PSCI_0_2_FN64_CPU_SUSPEND:
|
||||
val = kvm_psci_vcpu_suspend(vcpu);
|
||||
break;
|
||||
case PSCI_0_2_FN_CPU_OFF:
|
||||
kvm_psci_vcpu_off(vcpu);
|
||||
val = PSCI_RET_SUCCESS;
|
||||
break;
|
||||
case PSCI_0_2_FN_CPU_ON:
|
||||
case PSCI_0_2_FN64_CPU_ON:
|
||||
val = kvm_psci_vcpu_on(vcpu);
|
||||
break;
|
||||
case PSCI_0_2_FN_AFFINITY_INFO:
|
||||
case PSCI_0_2_FN64_AFFINITY_INFO:
|
||||
val = kvm_psci_vcpu_affinity_info(vcpu);
|
||||
break;
|
||||
case PSCI_0_2_FN_MIGRATE:
|
||||
case PSCI_0_2_FN64_MIGRATE:
|
||||
val = PSCI_RET_NOT_SUPPORTED;
|
||||
break;
|
||||
case PSCI_0_2_FN_MIGRATE_INFO_TYPE:
|
||||
/*
|
||||
* Trusted OS is MP hence does not require migration
|
||||
* or
|
||||
* Trusted OS is not present
|
||||
*/
|
||||
val = PSCI_0_2_TOS_MP;
|
||||
break;
|
||||
case PSCI_0_2_FN_MIGRATE_INFO_UP_CPU:
|
||||
case PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU:
|
||||
val = PSCI_RET_NOT_SUPPORTED;
|
||||
break;
|
||||
case PSCI_0_2_FN_SYSTEM_OFF:
|
||||
kvm_psci_system_off(vcpu);
|
||||
/*
|
||||
* We should'nt be going back to guest VCPU after
|
||||
* receiving SYSTEM_OFF request.
|
||||
*
|
||||
* If user space accidently/deliberately resumes
|
||||
* guest VCPU after SYSTEM_OFF request then guest
|
||||
* VCPU should see internal failure from PSCI return
|
||||
* value. To achieve this, we preload r0 (or x0) with
|
||||
* PSCI return value INTERNAL_FAILURE.
|
||||
*/
|
||||
val = PSCI_RET_INTERNAL_FAILURE;
|
||||
ret = 0;
|
||||
break;
|
||||
case PSCI_0_2_FN_SYSTEM_RESET:
|
||||
kvm_psci_system_reset(vcpu);
|
||||
/*
|
||||
* Same reason as SYSTEM_OFF for preloading r0 (or x0)
|
||||
* with PSCI return value INTERNAL_FAILURE.
|
||||
*/
|
||||
val = PSCI_RET_INTERNAL_FAILURE;
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*vcpu_reg(vcpu, 0) = val;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0);
|
||||
unsigned long val;
|
||||
|
|
@ -89,20 +275,45 @@ bool kvm_psci_call(struct kvm_vcpu *vcpu)
|
|||
switch (psci_fn) {
|
||||
case KVM_PSCI_FN_CPU_OFF:
|
||||
kvm_psci_vcpu_off(vcpu);
|
||||
val = KVM_PSCI_RET_SUCCESS;
|
||||
val = PSCI_RET_SUCCESS;
|
||||
break;
|
||||
case KVM_PSCI_FN_CPU_ON:
|
||||
val = kvm_psci_vcpu_on(vcpu);
|
||||
break;
|
||||
case KVM_PSCI_FN_CPU_SUSPEND:
|
||||
case KVM_PSCI_FN_MIGRATE:
|
||||
val = KVM_PSCI_RET_NI;
|
||||
val = PSCI_RET_NOT_SUPPORTED;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*vcpu_reg(vcpu, 0) = val;
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_psci_call - handle PSCI call if r0 value is in range
|
||||
* @vcpu: Pointer to the VCPU struct
|
||||
*
|
||||
* Handle PSCI calls from guests through traps from HVC instructions.
|
||||
* The calling convention is similar to SMC calls to the secure world
|
||||
* where the function number is placed in r0.
|
||||
*
|
||||
* This function returns: > 0 (success), 0 (success but exit to user
|
||||
* space), and < 0 (errors)
|
||||
*
|
||||
* Errors:
|
||||
* -EINVAL: Unrecognized PSCI function
|
||||
*/
|
||||
int kvm_psci_call(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
switch (kvm_psci_version(vcpu)) {
|
||||
case KVM_ARM_PSCI_0_2:
|
||||
return kvm_psci_0_2_call(vcpu);
|
||||
case KVM_ARM_PSCI_0_1:
|
||||
return kvm_psci_0_1_call(vcpu);
|
||||
default:
|
||||
return -EINVAL;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,16 +27,21 @@
|
|||
#include <asm/kvm_arm.h>
|
||||
#include <asm/kvm_coproc.h>
|
||||
|
||||
#include <kvm/arm_arch_timer.h>
|
||||
|
||||
/******************************************************************************
|
||||
* Cortex-A15 Reset Values
|
||||
* Cortex-A15 and Cortex-A7 Reset Values
|
||||
*/
|
||||
|
||||
static const int a15_max_cpu_idx = 3;
|
||||
|
||||
static struct kvm_regs a15_regs_reset = {
|
||||
static struct kvm_regs cortexa_regs_reset = {
|
||||
.usr_regs.ARM_cpsr = SVC_MODE | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT,
|
||||
};
|
||||
|
||||
static const struct kvm_irq_level cortexa_vtimer_irq = {
|
||||
{ .irq = 27 },
|
||||
.level = 1,
|
||||
};
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Exported reset function
|
||||
|
|
@ -51,24 +56,28 @@ static struct kvm_regs a15_regs_reset = {
|
|||
*/
|
||||
int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_regs *cpu_reset;
|
||||
struct kvm_regs *reset_regs;
|
||||
const struct kvm_irq_level *cpu_vtimer_irq;
|
||||
|
||||
switch (vcpu->arch.target) {
|
||||
case KVM_ARM_TARGET_CORTEX_A7:
|
||||
case KVM_ARM_TARGET_CORTEX_A15:
|
||||
if (vcpu->vcpu_id > a15_max_cpu_idx)
|
||||
return -EINVAL;
|
||||
cpu_reset = &a15_regs_reset;
|
||||
reset_regs = &cortexa_regs_reset;
|
||||
vcpu->arch.midr = read_cpuid_id();
|
||||
cpu_vtimer_irq = &cortexa_vtimer_irq;
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Reset core registers */
|
||||
memcpy(&vcpu->arch.regs, cpu_reset, sizeof(vcpu->arch.regs));
|
||||
memcpy(&vcpu->arch.regs, reset_regs, sizeof(vcpu->arch.regs));
|
||||
|
||||
/* Reset CP15 registers */
|
||||
kvm_reset_coprocs(vcpu);
|
||||
|
||||
/* Reset arch_timer context */
|
||||
kvm_timer_vcpu_reset(vcpu, cpu_vtimer_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,10 +59,9 @@ TRACE_EVENT(kvm_guest_fault,
|
|||
__entry->ipa = ipa;
|
||||
),
|
||||
|
||||
TP_printk("guest fault at PC %#08lx (hxfar %#08lx, "
|
||||
"ipa %#16llx, hsr %#08lx",
|
||||
__entry->vcpu_pc, __entry->hxfar,
|
||||
__entry->ipa, __entry->hsr)
|
||||
TP_printk("ipa %#llx, hsr %#08lx, hxfar %#08lx, pc %#08lx",
|
||||
__entry->ipa, __entry->hsr,
|
||||
__entry->hxfar, __entry->vcpu_pc)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_irq_line,
|
||||
|
|
|
|||
1499
arch/arm/kvm/vgic.c
1499
arch/arm/kvm/vgic.c
File diff suppressed because it is too large
Load Diff
|
|
@ -197,24 +197,24 @@
|
|||
|
||||
12: PLD( pld [r1, #124] )
|
||||
13: ldr4w r1, r4, r5, r6, r7, abort=19f
|
||||
mov r3, lr, pull #\pull
|
||||
mov r3, lr, lspull #\pull
|
||||
subs r2, r2, #32
|
||||
ldr4w r1, r8, r9, ip, lr, abort=19f
|
||||
orr r3, r3, r4, push #\push
|
||||
mov r4, r4, pull #\pull
|
||||
orr r4, r4, r5, push #\push
|
||||
mov r5, r5, pull #\pull
|
||||
orr r5, r5, r6, push #\push
|
||||
mov r6, r6, pull #\pull
|
||||
orr r6, r6, r7, push #\push
|
||||
mov r7, r7, pull #\pull
|
||||
orr r7, r7, r8, push #\push
|
||||
mov r8, r8, pull #\pull
|
||||
orr r8, r8, r9, push #\push
|
||||
mov r9, r9, pull #\pull
|
||||
orr r9, r9, ip, push #\push
|
||||
mov ip, ip, pull #\pull
|
||||
orr ip, ip, lr, push #\push
|
||||
orr r3, r3, r4, lspush #\push
|
||||
mov r4, r4, lspull #\pull
|
||||
orr r4, r4, r5, lspush #\push
|
||||
mov r5, r5, lspull #\pull
|
||||
orr r5, r5, r6, lspush #\push
|
||||
mov r6, r6, lspull #\pull
|
||||
orr r6, r6, r7, lspush #\push
|
||||
mov r7, r7, lspull #\pull
|
||||
orr r7, r7, r8, lspush #\push
|
||||
mov r8, r8, lspull #\pull
|
||||
orr r8, r8, r9, lspush #\push
|
||||
mov r9, r9, lspull #\pull
|
||||
orr r9, r9, ip, lspush #\push
|
||||
mov ip, ip, lspull #\pull
|
||||
orr ip, ip, lr, lspush #\push
|
||||
str8w r0, r3, r4, r5, r6, r7, r8, r9, ip, , abort=19f
|
||||
bge 12b
|
||||
PLD( cmn r2, #96 )
|
||||
|
|
@ -225,10 +225,10 @@
|
|||
14: ands ip, r2, #28
|
||||
beq 16f
|
||||
|
||||
15: mov r3, lr, pull #\pull
|
||||
15: mov r3, lr, lspull #\pull
|
||||
ldr1w r1, lr, abort=21f
|
||||
subs ip, ip, #4
|
||||
orr r3, r3, lr, push #\push
|
||||
orr r3, r3, lr, lspush #\push
|
||||
str1w r0, r3, abort=21f
|
||||
bgt 15b
|
||||
CALGN( cmp r2, #0 )
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ FN_ENTRY
|
|||
tst len, #2
|
||||
mov r5, r4, get_byte_0
|
||||
beq .Lexit
|
||||
adcs sum, sum, r4, push #16
|
||||
adcs sum, sum, r4, lspush #16
|
||||
strb r5, [dst], #1
|
||||
mov r5, r4, get_byte_1
|
||||
strb r5, [dst], #1
|
||||
|
|
@ -171,23 +171,23 @@ FN_ENTRY
|
|||
cmp ip, #2
|
||||
beq .Lsrc2_aligned
|
||||
bhi .Lsrc3_aligned
|
||||
mov r4, r5, pull #8 @ C = 0
|
||||
mov r4, r5, lspull #8 @ C = 0
|
||||
bics ip, len, #15
|
||||
beq 2f
|
||||
1: load4l r5, r6, r7, r8
|
||||
orr r4, r4, r5, push #24
|
||||
mov r5, r5, pull #8
|
||||
orr r5, r5, r6, push #24
|
||||
mov r6, r6, pull #8
|
||||
orr r6, r6, r7, push #24
|
||||
mov r7, r7, pull #8
|
||||
orr r7, r7, r8, push #24
|
||||
orr r4, r4, r5, lspush #24
|
||||
mov r5, r5, lspull #8
|
||||
orr r5, r5, r6, lspush #24
|
||||
mov r6, r6, lspull #8
|
||||
orr r6, r6, r7, lspush #24
|
||||
mov r7, r7, lspull #8
|
||||
orr r7, r7, r8, lspush #24
|
||||
stmia dst!, {r4, r5, r6, r7}
|
||||
adcs sum, sum, r4
|
||||
adcs sum, sum, r5
|
||||
adcs sum, sum, r6
|
||||
adcs sum, sum, r7
|
||||
mov r4, r8, pull #8
|
||||
mov r4, r8, lspull #8
|
||||
sub ip, ip, #16
|
||||
teq ip, #0
|
||||
bne 1b
|
||||
|
|
@ -196,50 +196,50 @@ FN_ENTRY
|
|||
tst ip, #8
|
||||
beq 3f
|
||||
load2l r5, r6
|
||||
orr r4, r4, r5, push #24
|
||||
mov r5, r5, pull #8
|
||||
orr r5, r5, r6, push #24
|
||||
orr r4, r4, r5, lspush #24
|
||||
mov r5, r5, lspull #8
|
||||
orr r5, r5, r6, lspush #24
|
||||
stmia dst!, {r4, r5}
|
||||
adcs sum, sum, r4
|
||||
adcs sum, sum, r5
|
||||
mov r4, r6, pull #8
|
||||
mov r4, r6, lspull #8
|
||||
tst ip, #4
|
||||
beq 4f
|
||||
3: load1l r5
|
||||
orr r4, r4, r5, push #24
|
||||
orr r4, r4, r5, lspush #24
|
||||
str r4, [dst], #4
|
||||
adcs sum, sum, r4
|
||||
mov r4, r5, pull #8
|
||||
mov r4, r5, lspull #8
|
||||
4: ands len, len, #3
|
||||
beq .Ldone
|
||||
mov r5, r4, get_byte_0
|
||||
tst len, #2
|
||||
beq .Lexit
|
||||
adcs sum, sum, r4, push #16
|
||||
adcs sum, sum, r4, lspush #16
|
||||
strb r5, [dst], #1
|
||||
mov r5, r4, get_byte_1
|
||||
strb r5, [dst], #1
|
||||
mov r5, r4, get_byte_2
|
||||
b .Lexit
|
||||
|
||||
.Lsrc2_aligned: mov r4, r5, pull #16
|
||||
.Lsrc2_aligned: mov r4, r5, lspull #16
|
||||
adds sum, sum, #0
|
||||
bics ip, len, #15
|
||||
beq 2f
|
||||
1: load4l r5, r6, r7, r8
|
||||
orr r4, r4, r5, push #16
|
||||
mov r5, r5, pull #16
|
||||
orr r5, r5, r6, push #16
|
||||
mov r6, r6, pull #16
|
||||
orr r6, r6, r7, push #16
|
||||
mov r7, r7, pull #16
|
||||
orr r7, r7, r8, push #16
|
||||
orr r4, r4, r5, lspush #16
|
||||
mov r5, r5, lspull #16
|
||||
orr r5, r5, r6, lspush #16
|
||||
mov r6, r6, lspull #16
|
||||
orr r6, r6, r7, lspush #16
|
||||
mov r7, r7, lspull #16
|
||||
orr r7, r7, r8, lspush #16
|
||||
stmia dst!, {r4, r5, r6, r7}
|
||||
adcs sum, sum, r4
|
||||
adcs sum, sum, r5
|
||||
adcs sum, sum, r6
|
||||
adcs sum, sum, r7
|
||||
mov r4, r8, pull #16
|
||||
mov r4, r8, lspull #16
|
||||
sub ip, ip, #16
|
||||
teq ip, #0
|
||||
bne 1b
|
||||
|
|
@ -248,20 +248,20 @@ FN_ENTRY
|
|||
tst ip, #8
|
||||
beq 3f
|
||||
load2l r5, r6
|
||||
orr r4, r4, r5, push #16
|
||||
mov r5, r5, pull #16
|
||||
orr r5, r5, r6, push #16
|
||||
orr r4, r4, r5, lspush #16
|
||||
mov r5, r5, lspull #16
|
||||
orr r5, r5, r6, lspush #16
|
||||
stmia dst!, {r4, r5}
|
||||
adcs sum, sum, r4
|
||||
adcs sum, sum, r5
|
||||
mov r4, r6, pull #16
|
||||
mov r4, r6, lspull #16
|
||||
tst ip, #4
|
||||
beq 4f
|
||||
3: load1l r5
|
||||
orr r4, r4, r5, push #16
|
||||
orr r4, r4, r5, lspush #16
|
||||
str r4, [dst], #4
|
||||
adcs sum, sum, r4
|
||||
mov r4, r5, pull #16
|
||||
mov r4, r5, lspull #16
|
||||
4: ands len, len, #3
|
||||
beq .Ldone
|
||||
mov r5, r4, get_byte_0
|
||||
|
|
@ -276,24 +276,24 @@ FN_ENTRY
|
|||
load1b r5
|
||||
b .Lexit
|
||||
|
||||
.Lsrc3_aligned: mov r4, r5, pull #24
|
||||
.Lsrc3_aligned: mov r4, r5, lspull #24
|
||||
adds sum, sum, #0
|
||||
bics ip, len, #15
|
||||
beq 2f
|
||||
1: load4l r5, r6, r7, r8
|
||||
orr r4, r4, r5, push #8
|
||||
mov r5, r5, pull #24
|
||||
orr r5, r5, r6, push #8
|
||||
mov r6, r6, pull #24
|
||||
orr r6, r6, r7, push #8
|
||||
mov r7, r7, pull #24
|
||||
orr r7, r7, r8, push #8
|
||||
orr r4, r4, r5, lspush #8
|
||||
mov r5, r5, lspull #24
|
||||
orr r5, r5, r6, lspush #8
|
||||
mov r6, r6, lspull #24
|
||||
orr r6, r6, r7, lspush #8
|
||||
mov r7, r7, lspull #24
|
||||
orr r7, r7, r8, lspush #8
|
||||
stmia dst!, {r4, r5, r6, r7}
|
||||
adcs sum, sum, r4
|
||||
adcs sum, sum, r5
|
||||
adcs sum, sum, r6
|
||||
adcs sum, sum, r7
|
||||
mov r4, r8, pull #24
|
||||
mov r4, r8, lspull #24
|
||||
sub ip, ip, #16
|
||||
teq ip, #0
|
||||
bne 1b
|
||||
|
|
@ -302,20 +302,20 @@ FN_ENTRY
|
|||
tst ip, #8
|
||||
beq 3f
|
||||
load2l r5, r6
|
||||
orr r4, r4, r5, push #8
|
||||
mov r5, r5, pull #24
|
||||
orr r5, r5, r6, push #8
|
||||
orr r4, r4, r5, lspush #8
|
||||
mov r5, r5, lspull #24
|
||||
orr r5, r5, r6, lspush #8
|
||||
stmia dst!, {r4, r5}
|
||||
adcs sum, sum, r4
|
||||
adcs sum, sum, r5
|
||||
mov r4, r6, pull #24
|
||||
mov r4, r6, lspull #24
|
||||
tst ip, #4
|
||||
beq 4f
|
||||
3: load1l r5
|
||||
orr r4, r4, r5, push #8
|
||||
orr r4, r4, r5, lspush #8
|
||||
str r4, [dst], #4
|
||||
adcs sum, sum, r4
|
||||
mov r4, r5, pull #24
|
||||
mov r4, r5, lspull #24
|
||||
4: ands len, len, #3
|
||||
beq .Ldone
|
||||
mov r5, r4, get_byte_0
|
||||
|
|
@ -326,7 +326,7 @@ FN_ENTRY
|
|||
load1l r4
|
||||
mov r5, r4, get_byte_0
|
||||
strb r5, [dst], #1
|
||||
adcs sum, sum, r4, push #24
|
||||
adcs sum, sum, r4, lspush #24
|
||||
mov r5, r4, get_byte_1
|
||||
b .Lexit
|
||||
FN_EXIT
|
||||
|
|
|
|||
|
|
@ -47,25 +47,25 @@ ENTRY(__raw_readsl)
|
|||
strb ip, [r1], #1
|
||||
|
||||
4: subs r2, r2, #1
|
||||
mov ip, r3, pull #24
|
||||
mov ip, r3, lspull #24
|
||||
ldrne r3, [r0]
|
||||
orrne ip, ip, r3, push #8
|
||||
orrne ip, ip, r3, lspush #8
|
||||
strne ip, [r1], #4
|
||||
bne 4b
|
||||
b 8f
|
||||
|
||||
5: subs r2, r2, #1
|
||||
mov ip, r3, pull #16
|
||||
mov ip, r3, lspull #16
|
||||
ldrne r3, [r0]
|
||||
orrne ip, ip, r3, push #16
|
||||
orrne ip, ip, r3, lspush #16
|
||||
strne ip, [r1], #4
|
||||
bne 5b
|
||||
b 7f
|
||||
|
||||
6: subs r2, r2, #1
|
||||
mov ip, r3, pull #8
|
||||
mov ip, r3, lspull #8
|
||||
ldrne r3, [r0]
|
||||
orrne ip, ip, r3, push #24
|
||||
orrne ip, ip, r3, lspush #24
|
||||
strne ip, [r1], #4
|
||||
bne 6b
|
||||
|
||||
|
|
|
|||
|
|
@ -41,26 +41,26 @@ ENTRY(__raw_writesl)
|
|||
blt 5f
|
||||
bgt 6f
|
||||
|
||||
4: mov ip, r3, pull #16
|
||||
4: mov ip, r3, lspull #16
|
||||
ldr r3, [r1], #4
|
||||
subs r2, r2, #1
|
||||
orr ip, ip, r3, push #16
|
||||
orr ip, ip, r3, lspush #16
|
||||
str ip, [r0]
|
||||
bne 4b
|
||||
mov pc, lr
|
||||
|
||||
5: mov ip, r3, pull #8
|
||||
5: mov ip, r3, lspull #8
|
||||
ldr r3, [r1], #4
|
||||
subs r2, r2, #1
|
||||
orr ip, ip, r3, push #24
|
||||
orr ip, ip, r3, lspush #24
|
||||
str ip, [r0]
|
||||
bne 5b
|
||||
mov pc, lr
|
||||
|
||||
6: mov ip, r3, pull #24
|
||||
6: mov ip, r3, lspull #24
|
||||
ldr r3, [r1], #4
|
||||
subs r2, r2, #1
|
||||
orr ip, ip, r3, push #8
|
||||
orr ip, ip, r3, lspush #8
|
||||
str ip, [r0]
|
||||
bne 6b
|
||||
mov pc, lr
|
||||
|
|
|
|||
|
|
@ -147,24 +147,24 @@ ENTRY(memmove)
|
|||
|
||||
12: PLD( pld [r1, #-128] )
|
||||
13: ldmdb r1!, {r7, r8, r9, ip}
|
||||
mov lr, r3, push #\push
|
||||
mov lr, r3, lspush #\push
|
||||
subs r2, r2, #32
|
||||
ldmdb r1!, {r3, r4, r5, r6}
|
||||
orr lr, lr, ip, pull #\pull
|
||||
mov ip, ip, push #\push
|
||||
orr ip, ip, r9, pull #\pull
|
||||
mov r9, r9, push #\push
|
||||
orr r9, r9, r8, pull #\pull
|
||||
mov r8, r8, push #\push
|
||||
orr r8, r8, r7, pull #\pull
|
||||
mov r7, r7, push #\push
|
||||
orr r7, r7, r6, pull #\pull
|
||||
mov r6, r6, push #\push
|
||||
orr r6, r6, r5, pull #\pull
|
||||
mov r5, r5, push #\push
|
||||
orr r5, r5, r4, pull #\pull
|
||||
mov r4, r4, push #\push
|
||||
orr r4, r4, r3, pull #\pull
|
||||
orr lr, lr, ip, lspull #\pull
|
||||
mov ip, ip, lspush #\push
|
||||
orr ip, ip, r9, lspull #\pull
|
||||
mov r9, r9, lspush #\push
|
||||
orr r9, r9, r8, lspull #\pull
|
||||
mov r8, r8, lspush #\push
|
||||
orr r8, r8, r7, lspull #\pull
|
||||
mov r7, r7, lspush #\push
|
||||
orr r7, r7, r6, lspull #\pull
|
||||
mov r6, r6, lspush #\push
|
||||
orr r6, r6, r5, lspull #\pull
|
||||
mov r5, r5, lspush #\push
|
||||
orr r5, r5, r4, lspull #\pull
|
||||
mov r4, r4, lspush #\push
|
||||
orr r4, r4, r3, lspull #\pull
|
||||
stmdb r0!, {r4 - r9, ip, lr}
|
||||
bge 12b
|
||||
PLD( cmn r2, #96 )
|
||||
|
|
@ -175,10 +175,10 @@ ENTRY(memmove)
|
|||
14: ands ip, r2, #28
|
||||
beq 16f
|
||||
|
||||
15: mov lr, r3, push #\push
|
||||
15: mov lr, r3, lspush #\push
|
||||
ldr r3, [r1, #-4]!
|
||||
subs ip, ip, #4
|
||||
orr lr, lr, r3, pull #\pull
|
||||
orr lr, lr, r3, lspull #\pull
|
||||
str lr, [r0, #-4]!
|
||||
bgt 15b
|
||||
CALGN( cmp r2, #0 )
|
||||
|
|
|
|||
|
|
@ -117,9 +117,9 @@ USER( TUSER( strgtb) r3, [r0], #1) @ May fault
|
|||
.Lc2u_1fupi: subs r2, r2, #4
|
||||
addmi ip, r2, #4
|
||||
bmi .Lc2u_1nowords
|
||||
mov r3, r7, pull #8
|
||||
mov r3, r7, lspull #8
|
||||
ldr r7, [r1], #4
|
||||
orr r3, r3, r7, push #24
|
||||
orr r3, r3, r7, lspush #24
|
||||
USER( TUSER( str) r3, [r0], #4) @ May fault
|
||||
mov ip, r0, lsl #32 - PAGE_SHIFT
|
||||
rsb ip, ip, #0
|
||||
|
|
@ -131,30 +131,30 @@ USER( TUSER( str) r3, [r0], #4) @ May fault
|
|||
subs ip, ip, #16
|
||||
blt .Lc2u_1rem8lp
|
||||
|
||||
.Lc2u_1cpy8lp: mov r3, r7, pull #8
|
||||
.Lc2u_1cpy8lp: mov r3, r7, lspull #8
|
||||
ldmia r1!, {r4 - r7}
|
||||
subs ip, ip, #16
|
||||
orr r3, r3, r4, push #24
|
||||
mov r4, r4, pull #8
|
||||
orr r4, r4, r5, push #24
|
||||
mov r5, r5, pull #8
|
||||
orr r5, r5, r6, push #24
|
||||
mov r6, r6, pull #8
|
||||
orr r6, r6, r7, push #24
|
||||
orr r3, r3, r4, lspush #24
|
||||
mov r4, r4, lspull #8
|
||||
orr r4, r4, r5, lspush #24
|
||||
mov r5, r5, lspull #8
|
||||
orr r5, r5, r6, lspush #24
|
||||
mov r6, r6, lspull #8
|
||||
orr r6, r6, r7, lspush #24
|
||||
stmia r0!, {r3 - r6} @ Shouldnt fault
|
||||
bpl .Lc2u_1cpy8lp
|
||||
|
||||
.Lc2u_1rem8lp: tst ip, #8
|
||||
movne r3, r7, pull #8
|
||||
movne r3, r7, lspull #8
|
||||
ldmneia r1!, {r4, r7}
|
||||
orrne r3, r3, r4, push #24
|
||||
movne r4, r4, pull #8
|
||||
orrne r4, r4, r7, push #24
|
||||
orrne r3, r3, r4, lspush #24
|
||||
movne r4, r4, lspull #8
|
||||
orrne r4, r4, r7, lspush #24
|
||||
stmneia r0!, {r3 - r4} @ Shouldnt fault
|
||||
tst ip, #4
|
||||
movne r3, r7, pull #8
|
||||
movne r3, r7, lspull #8
|
||||
ldrne r7, [r1], #4
|
||||
orrne r3, r3, r7, push #24
|
||||
orrne r3, r3, r7, lspush #24
|
||||
TUSER( strne) r3, [r0], #4 @ Shouldnt fault
|
||||
ands ip, ip, #3
|
||||
beq .Lc2u_1fupi
|
||||
|
|
@ -172,9 +172,9 @@ USER( TUSER( strgtb) r3, [r0], #1) @ May fault
|
|||
.Lc2u_2fupi: subs r2, r2, #4
|
||||
addmi ip, r2, #4
|
||||
bmi .Lc2u_2nowords
|
||||
mov r3, r7, pull #16
|
||||
mov r3, r7, lspull #16
|
||||
ldr r7, [r1], #4
|
||||
orr r3, r3, r7, push #16
|
||||
orr r3, r3, r7, lspush #16
|
||||
USER( TUSER( str) r3, [r0], #4) @ May fault
|
||||
mov ip, r0, lsl #32 - PAGE_SHIFT
|
||||
rsb ip, ip, #0
|
||||
|
|
@ -186,30 +186,30 @@ USER( TUSER( str) r3, [r0], #4) @ May fault
|
|||
subs ip, ip, #16
|
||||
blt .Lc2u_2rem8lp
|
||||
|
||||
.Lc2u_2cpy8lp: mov r3, r7, pull #16
|
||||
.Lc2u_2cpy8lp: mov r3, r7, lspull #16
|
||||
ldmia r1!, {r4 - r7}
|
||||
subs ip, ip, #16
|
||||
orr r3, r3, r4, push #16
|
||||
mov r4, r4, pull #16
|
||||
orr r4, r4, r5, push #16
|
||||
mov r5, r5, pull #16
|
||||
orr r5, r5, r6, push #16
|
||||
mov r6, r6, pull #16
|
||||
orr r6, r6, r7, push #16
|
||||
orr r3, r3, r4, lspush #16
|
||||
mov r4, r4, lspull #16
|
||||
orr r4, r4, r5, lspush #16
|
||||
mov r5, r5, lspull #16
|
||||
orr r5, r5, r6, lspush #16
|
||||
mov r6, r6, lspull #16
|
||||
orr r6, r6, r7, lspush #16
|
||||
stmia r0!, {r3 - r6} @ Shouldnt fault
|
||||
bpl .Lc2u_2cpy8lp
|
||||
|
||||
.Lc2u_2rem8lp: tst ip, #8
|
||||
movne r3, r7, pull #16
|
||||
movne r3, r7, lspull #16
|
||||
ldmneia r1!, {r4, r7}
|
||||
orrne r3, r3, r4, push #16
|
||||
movne r4, r4, pull #16
|
||||
orrne r4, r4, r7, push #16
|
||||
orrne r3, r3, r4, lspush #16
|
||||
movne r4, r4, lspull #16
|
||||
orrne r4, r4, r7, lspush #16
|
||||
stmneia r0!, {r3 - r4} @ Shouldnt fault
|
||||
tst ip, #4
|
||||
movne r3, r7, pull #16
|
||||
movne r3, r7, lspull #16
|
||||
ldrne r7, [r1], #4
|
||||
orrne r3, r3, r7, push #16
|
||||
orrne r3, r3, r7, lspush #16
|
||||
TUSER( strne) r3, [r0], #4 @ Shouldnt fault
|
||||
ands ip, ip, #3
|
||||
beq .Lc2u_2fupi
|
||||
|
|
@ -227,9 +227,9 @@ USER( TUSER( strgtb) r3, [r0], #1) @ May fault
|
|||
.Lc2u_3fupi: subs r2, r2, #4
|
||||
addmi ip, r2, #4
|
||||
bmi .Lc2u_3nowords
|
||||
mov r3, r7, pull #24
|
||||
mov r3, r7, lspull #24
|
||||
ldr r7, [r1], #4
|
||||
orr r3, r3, r7, push #8
|
||||
orr r3, r3, r7, lspush #8
|
||||
USER( TUSER( str) r3, [r0], #4) @ May fault
|
||||
mov ip, r0, lsl #32 - PAGE_SHIFT
|
||||
rsb ip, ip, #0
|
||||
|
|
@ -241,30 +241,30 @@ USER( TUSER( str) r3, [r0], #4) @ May fault
|
|||
subs ip, ip, #16
|
||||
blt .Lc2u_3rem8lp
|
||||
|
||||
.Lc2u_3cpy8lp: mov r3, r7, pull #24
|
||||
.Lc2u_3cpy8lp: mov r3, r7, lspull #24
|
||||
ldmia r1!, {r4 - r7}
|
||||
subs ip, ip, #16
|
||||
orr r3, r3, r4, push #8
|
||||
mov r4, r4, pull #24
|
||||
orr r4, r4, r5, push #8
|
||||
mov r5, r5, pull #24
|
||||
orr r5, r5, r6, push #8
|
||||
mov r6, r6, pull #24
|
||||
orr r6, r6, r7, push #8
|
||||
orr r3, r3, r4, lspush #8
|
||||
mov r4, r4, lspull #24
|
||||
orr r4, r4, r5, lspush #8
|
||||
mov r5, r5, lspull #24
|
||||
orr r5, r5, r6, lspush #8
|
||||
mov r6, r6, lspull #24
|
||||
orr r6, r6, r7, lspush #8
|
||||
stmia r0!, {r3 - r6} @ Shouldnt fault
|
||||
bpl .Lc2u_3cpy8lp
|
||||
|
||||
.Lc2u_3rem8lp: tst ip, #8
|
||||
movne r3, r7, pull #24
|
||||
movne r3, r7, lspull #24
|
||||
ldmneia r1!, {r4, r7}
|
||||
orrne r3, r3, r4, push #8
|
||||
movne r4, r4, pull #24
|
||||
orrne r4, r4, r7, push #8
|
||||
orrne r3, r3, r4, lspush #8
|
||||
movne r4, r4, lspull #24
|
||||
orrne r4, r4, r7, lspush #8
|
||||
stmneia r0!, {r3 - r4} @ Shouldnt fault
|
||||
tst ip, #4
|
||||
movne r3, r7, pull #24
|
||||
movne r3, r7, lspull #24
|
||||
ldrne r7, [r1], #4
|
||||
orrne r3, r3, r7, push #8
|
||||
orrne r3, r3, r7, lspush #8
|
||||
TUSER( strne) r3, [r0], #4 @ Shouldnt fault
|
||||
ands ip, ip, #3
|
||||
beq .Lc2u_3fupi
|
||||
|
|
@ -382,9 +382,9 @@ USER( TUSER( ldr) r7, [r1], #4) @ May fault
|
|||
.Lcfu_1fupi: subs r2, r2, #4
|
||||
addmi ip, r2, #4
|
||||
bmi .Lcfu_1nowords
|
||||
mov r3, r7, pull #8
|
||||
mov r3, r7, lspull #8
|
||||
USER( TUSER( ldr) r7, [r1], #4) @ May fault
|
||||
orr r3, r3, r7, push #24
|
||||
orr r3, r3, r7, lspush #24
|
||||
str r3, [r0], #4
|
||||
mov ip, r1, lsl #32 - PAGE_SHIFT
|
||||
rsb ip, ip, #0
|
||||
|
|
@ -396,30 +396,30 @@ USER( TUSER( ldr) r7, [r1], #4) @ May fault
|
|||
subs ip, ip, #16
|
||||
blt .Lcfu_1rem8lp
|
||||
|
||||
.Lcfu_1cpy8lp: mov r3, r7, pull #8
|
||||
.Lcfu_1cpy8lp: mov r3, r7, lspull #8
|
||||
ldmia r1!, {r4 - r7} @ Shouldnt fault
|
||||
subs ip, ip, #16
|
||||
orr r3, r3, r4, push #24
|
||||
mov r4, r4, pull #8
|
||||
orr r4, r4, r5, push #24
|
||||
mov r5, r5, pull #8
|
||||
orr r5, r5, r6, push #24
|
||||
mov r6, r6, pull #8
|
||||
orr r6, r6, r7, push #24
|
||||
orr r3, r3, r4, lspush #24
|
||||
mov r4, r4, lspull #8
|
||||
orr r4, r4, r5, lspush #24
|
||||
mov r5, r5, lspull #8
|
||||
orr r5, r5, r6, lspush #24
|
||||
mov r6, r6, lspull #8
|
||||
orr r6, r6, r7, lspush #24
|
||||
stmia r0!, {r3 - r6}
|
||||
bpl .Lcfu_1cpy8lp
|
||||
|
||||
.Lcfu_1rem8lp: tst ip, #8
|
||||
movne r3, r7, pull #8
|
||||
movne r3, r7, lspull #8
|
||||
ldmneia r1!, {r4, r7} @ Shouldnt fault
|
||||
orrne r3, r3, r4, push #24
|
||||
movne r4, r4, pull #8
|
||||
orrne r4, r4, r7, push #24
|
||||
orrne r3, r3, r4, lspush #24
|
||||
movne r4, r4, lspull #8
|
||||
orrne r4, r4, r7, lspush #24
|
||||
stmneia r0!, {r3 - r4}
|
||||
tst ip, #4
|
||||
movne r3, r7, pull #8
|
||||
movne r3, r7, lspull #8
|
||||
USER( TUSER( ldrne) r7, [r1], #4) @ May fault
|
||||
orrne r3, r3, r7, push #24
|
||||
orrne r3, r3, r7, lspush #24
|
||||
strne r3, [r0], #4
|
||||
ands ip, ip, #3
|
||||
beq .Lcfu_1fupi
|
||||
|
|
@ -437,9 +437,9 @@ USER( TUSER( ldrne) r7, [r1], #4) @ May fault
|
|||
.Lcfu_2fupi: subs r2, r2, #4
|
||||
addmi ip, r2, #4
|
||||
bmi .Lcfu_2nowords
|
||||
mov r3, r7, pull #16
|
||||
mov r3, r7, lspull #16
|
||||
USER( TUSER( ldr) r7, [r1], #4) @ May fault
|
||||
orr r3, r3, r7, push #16
|
||||
orr r3, r3, r7, lspush #16
|
||||
str r3, [r0], #4
|
||||
mov ip, r1, lsl #32 - PAGE_SHIFT
|
||||
rsb ip, ip, #0
|
||||
|
|
@ -452,30 +452,30 @@ USER( TUSER( ldr) r7, [r1], #4) @ May fault
|
|||
blt .Lcfu_2rem8lp
|
||||
|
||||
|
||||
.Lcfu_2cpy8lp: mov r3, r7, pull #16
|
||||
.Lcfu_2cpy8lp: mov r3, r7, lspull #16
|
||||
ldmia r1!, {r4 - r7} @ Shouldnt fault
|
||||
subs ip, ip, #16
|
||||
orr r3, r3, r4, push #16
|
||||
mov r4, r4, pull #16
|
||||
orr r4, r4, r5, push #16
|
||||
mov r5, r5, pull #16
|
||||
orr r5, r5, r6, push #16
|
||||
mov r6, r6, pull #16
|
||||
orr r6, r6, r7, push #16
|
||||
orr r3, r3, r4, lspush #16
|
||||
mov r4, r4, lspull #16
|
||||
orr r4, r4, r5, lspush #16
|
||||
mov r5, r5, lspull #16
|
||||
orr r5, r5, r6, lspush #16
|
||||
mov r6, r6, lspull #16
|
||||
orr r6, r6, r7, lspush #16
|
||||
stmia r0!, {r3 - r6}
|
||||
bpl .Lcfu_2cpy8lp
|
||||
|
||||
.Lcfu_2rem8lp: tst ip, #8
|
||||
movne r3, r7, pull #16
|
||||
movne r3, r7, lspull #16
|
||||
ldmneia r1!, {r4, r7} @ Shouldnt fault
|
||||
orrne r3, r3, r4, push #16
|
||||
movne r4, r4, pull #16
|
||||
orrne r4, r4, r7, push #16
|
||||
orrne r3, r3, r4, lspush #16
|
||||
movne r4, r4, lspull #16
|
||||
orrne r4, r4, r7, lspush #16
|
||||
stmneia r0!, {r3 - r4}
|
||||
tst ip, #4
|
||||
movne r3, r7, pull #16
|
||||
movne r3, r7, lspull #16
|
||||
USER( TUSER( ldrne) r7, [r1], #4) @ May fault
|
||||
orrne r3, r3, r7, push #16
|
||||
orrne r3, r3, r7, lspush #16
|
||||
strne r3, [r0], #4
|
||||
ands ip, ip, #3
|
||||
beq .Lcfu_2fupi
|
||||
|
|
@ -493,9 +493,9 @@ USER( TUSER( ldrgtb) r3, [r1], #0) @ May fault
|
|||
.Lcfu_3fupi: subs r2, r2, #4
|
||||
addmi ip, r2, #4
|
||||
bmi .Lcfu_3nowords
|
||||
mov r3, r7, pull #24
|
||||
mov r3, r7, lspull #24
|
||||
USER( TUSER( ldr) r7, [r1], #4) @ May fault
|
||||
orr r3, r3, r7, push #8
|
||||
orr r3, r3, r7, lspush #8
|
||||
str r3, [r0], #4
|
||||
mov ip, r1, lsl #32 - PAGE_SHIFT
|
||||
rsb ip, ip, #0
|
||||
|
|
@ -507,30 +507,30 @@ USER( TUSER( ldr) r7, [r1], #4) @ May fault
|
|||
subs ip, ip, #16
|
||||
blt .Lcfu_3rem8lp
|
||||
|
||||
.Lcfu_3cpy8lp: mov r3, r7, pull #24
|
||||
.Lcfu_3cpy8lp: mov r3, r7, lspull #24
|
||||
ldmia r1!, {r4 - r7} @ Shouldnt fault
|
||||
orr r3, r3, r4, push #8
|
||||
mov r4, r4, pull #24
|
||||
orr r4, r4, r5, push #8
|
||||
mov r5, r5, pull #24
|
||||
orr r5, r5, r6, push #8
|
||||
mov r6, r6, pull #24
|
||||
orr r6, r6, r7, push #8
|
||||
orr r3, r3, r4, lspush #8
|
||||
mov r4, r4, lspull #24
|
||||
orr r4, r4, r5, lspush #8
|
||||
mov r5, r5, lspull #24
|
||||
orr r5, r5, r6, lspush #8
|
||||
mov r6, r6, lspull #24
|
||||
orr r6, r6, r7, lspush #8
|
||||
stmia r0!, {r3 - r6}
|
||||
subs ip, ip, #16
|
||||
bpl .Lcfu_3cpy8lp
|
||||
|
||||
.Lcfu_3rem8lp: tst ip, #8
|
||||
movne r3, r7, pull #24
|
||||
movne r3, r7, lspull #24
|
||||
ldmneia r1!, {r4, r7} @ Shouldnt fault
|
||||
orrne r3, r3, r4, push #8
|
||||
movne r4, r4, pull #24
|
||||
orrne r4, r4, r7, push #8
|
||||
orrne r3, r3, r4, lspush #8
|
||||
movne r4, r4, lspull #24
|
||||
orrne r4, r4, r7, lspush #8
|
||||
stmneia r0!, {r3 - r4}
|
||||
tst ip, #4
|
||||
movne r3, r7, pull #24
|
||||
movne r3, r7, lspull #24
|
||||
USER( TUSER( ldrne) r7, [r1], #4) @ May fault
|
||||
orrne r3, r3, r7, push #8
|
||||
orrne r3, r3, r7, lspush #8
|
||||
strne r3, [r0], #4
|
||||
ands ip, ip, #3
|
||||
beq .Lcfu_3fupi
|
||||
|
|
|
|||
|
|
@ -947,6 +947,7 @@ static int __init at91_clock_reset(void)
|
|||
}
|
||||
|
||||
at91_pmc_write(AT91_PMC_SCDR, scdr);
|
||||
at91_pmc_write(AT91_PMC_PCDR, pcdr);
|
||||
if (cpu_is_sama5d3())
|
||||
at91_pmc_write(AT91_PMC_PCDR1, pcdr1);
|
||||
|
||||
|
|
|
|||
|
|
@ -323,7 +323,8 @@ void omap3_save_scratchpad_contents(void)
|
|||
scratchpad_contents.public_restore_ptr =
|
||||
virt_to_phys(omap3_restore_3630);
|
||||
else if (omap_rev() != OMAP3430_REV_ES3_0 &&
|
||||
omap_rev() != OMAP3430_REV_ES3_1)
|
||||
omap_rev() != OMAP3430_REV_ES3_1 &&
|
||||
omap_rev() != OMAP3430_REV_ES3_1_2)
|
||||
scratchpad_contents.public_restore_ptr =
|
||||
virt_to_phys(omap3_restore);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -2177,6 +2177,8 @@ static int _enable(struct omap_hwmod *oh)
|
|||
oh->mux->pads_dynamic))) {
|
||||
omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED);
|
||||
_reconfigure_io_chain();
|
||||
} else if (oh->flags & HWMOD_FORCE_MSTANDBY) {
|
||||
_reconfigure_io_chain();
|
||||
}
|
||||
|
||||
_add_initiator_dep(oh, mpu_oh);
|
||||
|
|
@ -2283,6 +2285,8 @@ static int _idle(struct omap_hwmod *oh)
|
|||
if (oh->mux && oh->mux->pads_dynamic) {
|
||||
omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE);
|
||||
_reconfigure_io_chain();
|
||||
} else if (oh->flags & HWMOD_FORCE_MSTANDBY) {
|
||||
_reconfigure_io_chain();
|
||||
}
|
||||
|
||||
oh->_state = _HWMOD_STATE_IDLE;
|
||||
|
|
|
|||
|
|
@ -778,6 +778,7 @@ config NEED_KUSER_HELPERS
|
|||
|
||||
config KUSER_HELPERS
|
||||
bool "Enable kuser helpers in vector page" if !NEED_KUSER_HELPERS
|
||||
depends on MMU
|
||||
default y
|
||||
help
|
||||
Warning: disabling this option may break user programs.
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ obj-$(CONFIG_MODULES) += proc-syms.o
|
|||
|
||||
obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o
|
||||
obj-$(CONFIG_HIGHMEM) += highmem.o
|
||||
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
|
||||
|
||||
obj-$(CONFIG_CPU_ABRT_NOMMU) += abort-nommu.o
|
||||
obj-$(CONFIG_CPU_ABRT_EV4) += abort-ev4.o
|
||||
|
|
|
|||
|
|
@ -17,12 +17,6 @@
|
|||
*/
|
||||
.align 5
|
||||
ENTRY(v6_early_abort)
|
||||
#ifdef CONFIG_CPU_V6
|
||||
sub r1, sp, #4 @ Get unused stack location
|
||||
strex r0, r1, [r1] @ Clear the exclusive monitor
|
||||
#elif defined(CONFIG_CPU_32v6K)
|
||||
clrex
|
||||
#endif
|
||||
mrc p15, 0, r1, c5, c0, 0 @ get FSR
|
||||
mrc p15, 0, r0, c6, c0, 0 @ get FAR
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -13,12 +13,6 @@
|
|||
*/
|
||||
.align 5
|
||||
ENTRY(v7_early_abort)
|
||||
/*
|
||||
* The effect of data aborts on on the exclusive access monitor are
|
||||
* UNPREDICTABLE. Do a CLREX to clear the state
|
||||
*/
|
||||
clrex
|
||||
|
||||
mrc p15, 0, r1, c5, c0, 0 @ get FSR
|
||||
mrc p15, 0, r0, c6, c0, 0 @ get FAR
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
* This code is not portable to processors with late data abort handling.
|
||||
*/
|
||||
#define CODING_BITS(i) (i & 0x0e000000)
|
||||
#define COND_BITS(i) (i & 0xf0000000)
|
||||
|
||||
#define LDST_I_BIT(i) (i & (1 << 26)) /* Immediate constant */
|
||||
#define LDST_P_BIT(i) (i & (1 << 24)) /* Preindex */
|
||||
|
|
@ -817,6 +818,8 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
|||
break;
|
||||
|
||||
case 0x04000000: /* ldr or str immediate */
|
||||
if (COND_BITS(instr) == 0xf0000000) /* NEON VLDn, VSTn */
|
||||
goto bad;
|
||||
offset.un = OFFSET_BITS(instr);
|
||||
handler = do_alignment_ldrstr;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ static void __dma_free_buffer(struct page *page, size_t size)
|
|||
|
||||
#ifdef CONFIG_MMU
|
||||
#ifdef CONFIG_HUGETLB_PAGE
|
||||
#error ARM Coherent DMA allocator does not (yet) support huge TLB
|
||||
#warning ARM Coherent DMA allocator does not (yet) support huge TLB
|
||||
#endif
|
||||
|
||||
static void *__alloc_from_contiguous(struct device *dev, size_t size,
|
||||
|
|
|
|||
|
|
@ -261,9 +261,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
|||
struct task_struct *tsk;
|
||||
struct mm_struct *mm;
|
||||
int fault, sig, code;
|
||||
int write = fsr & FSR_WRITE;
|
||||
unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
|
||||
(write ? FAULT_FLAG_WRITE : 0);
|
||||
unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
|
||||
|
||||
if (notify_page_fault(regs, fsr))
|
||||
return 0;
|
||||
|
|
@ -282,6 +280,11 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
|||
if (in_atomic() || irqs_disabled() || !mm)
|
||||
goto no_context;
|
||||
|
||||
if (user_mode(regs))
|
||||
flags |= FAULT_FLAG_USER;
|
||||
if (fsr & FSR_WRITE)
|
||||
flags |= FAULT_FLAG_WRITE;
|
||||
|
||||
/*
|
||||
* As per x86, we may deadlock here. However, since the kernel only
|
||||
* validly references user space from well defined areas of the code,
|
||||
|
|
@ -349,6 +352,13 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
|||
if (likely(!(fault & (VM_FAULT_ERROR | VM_FAULT_BADMAP | VM_FAULT_BADACCESS))))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If we are in kernel mode at this point, we
|
||||
* have no context to handle this fault with.
|
||||
*/
|
||||
if (!user_mode(regs))
|
||||
goto no_context;
|
||||
|
||||
if (fault & VM_FAULT_OOM) {
|
||||
/*
|
||||
* We ran out of memory, call the OOM killer, and return to
|
||||
|
|
@ -359,13 +369,6 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are in kernel mode at this point, we
|
||||
* have no context to handle this fault with.
|
||||
*/
|
||||
if (!user_mode(regs))
|
||||
goto no_context;
|
||||
|
||||
if (fault & VM_FAULT_SIGBUS) {
|
||||
/*
|
||||
* We had some memory, but were unable to
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include <asm/highmem.h>
|
||||
#include <asm/smp_plat.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <linux/hugetlb.h>
|
||||
|
||||
#include "mm.h"
|
||||
|
||||
|
|
@ -168,19 +169,23 @@ void __flush_dcache_page(struct address_space *mapping, struct page *page)
|
|||
* coherent with the kernels mapping.
|
||||
*/
|
||||
if (!PageHighMem(page)) {
|
||||
__cpuc_flush_dcache_area(page_address(page), PAGE_SIZE);
|
||||
size_t page_size = PAGE_SIZE << compound_order(page);
|
||||
__cpuc_flush_dcache_area(page_address(page), page_size);
|
||||
} else {
|
||||
void *addr;
|
||||
|
||||
unsigned long i;
|
||||
if (cache_is_vipt_nonaliasing()) {
|
||||
addr = kmap_atomic(page);
|
||||
__cpuc_flush_dcache_area(addr, PAGE_SIZE);
|
||||
kunmap_atomic(addr);
|
||||
} else {
|
||||
addr = kmap_high_get(page);
|
||||
if (addr) {
|
||||
for (i = 0; i < (1 << compound_order(page)); i++) {
|
||||
void *addr = kmap_atomic(page);
|
||||
__cpuc_flush_dcache_area(addr, PAGE_SIZE);
|
||||
kunmap_high(page);
|
||||
kunmap_atomic(addr);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < (1 << compound_order(page)); i++) {
|
||||
void *addr = kmap_high_get(page);
|
||||
if (addr) {
|
||||
__cpuc_flush_dcache_area(addr, PAGE_SIZE);
|
||||
kunmap_high(page);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@ static struct fsr_info fsr_info[] = {
|
|||
{ do_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" },
|
||||
{ do_bad, SIGBUS, 0, "reserved access flag fault" },
|
||||
{ do_bad, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" },
|
||||
{ do_bad, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },
|
||||
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },
|
||||
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" },
|
||||
{ do_bad, SIGBUS, 0, "reserved permission fault" },
|
||||
{ do_bad, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" },
|
||||
{ do_sect_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
|
||||
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
|
||||
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" },
|
||||
{ do_bad, SIGBUS, 0, "synchronous external abort" },
|
||||
{ do_bad, SIGBUS, 0, "asynchronous external abort" },
|
||||
|
|
|
|||
101
arch/arm/mm/hugetlbpage.c
Normal file
101
arch/arm/mm/hugetlbpage.c
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* arch/arm/mm/hugetlbpage.c
|
||||
*
|
||||
* Copyright (C) 2012 ARM Ltd.
|
||||
*
|
||||
* Based on arch/x86/include/asm/hugetlb.h and Bill Carson's patches
|
||||
*
|
||||
* 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/hugetlb.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <asm/mman.h>
|
||||
#include <asm/tlb.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/pgalloc.h>
|
||||
|
||||
/*
|
||||
* On ARM, huge pages are backed by pmd's rather than pte's, so we do a lot
|
||||
* of type casting from pmd_t * to pte_t *.
|
||||
*/
|
||||
|
||||
pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
|
||||
{
|
||||
pgd_t *pgd;
|
||||
pud_t *pud;
|
||||
pmd_t *pmd = NULL;
|
||||
|
||||
pgd = pgd_offset(mm, addr);
|
||||
if (pgd_present(*pgd)) {
|
||||
pud = pud_offset(pgd, addr);
|
||||
if (pud_present(*pud))
|
||||
pmd = pmd_offset(pud, addr);
|
||||
}
|
||||
|
||||
return (pte_t *)pmd;
|
||||
}
|
||||
|
||||
struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address,
|
||||
int write)
|
||||
{
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
int pud_huge(pud_t pud)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
pte_t *huge_pte_alloc(struct mm_struct *mm,
|
||||
unsigned long addr, unsigned long sz)
|
||||
{
|
||||
pgd_t *pgd;
|
||||
pud_t *pud;
|
||||
pte_t *pte = NULL;
|
||||
|
||||
pgd = pgd_offset(mm, addr);
|
||||
pud = pud_alloc(mm, pgd, addr);
|
||||
if (pud)
|
||||
pte = (pte_t *)pmd_alloc(mm, pud, addr);
|
||||
|
||||
return pte;
|
||||
}
|
||||
|
||||
struct page *
|
||||
follow_huge_pmd(struct mm_struct *mm, unsigned long address,
|
||||
pmd_t *pmd, int write)
|
||||
{
|
||||
struct page *page;
|
||||
|
||||
page = pte_page(*(pte_t *)pmd);
|
||||
if (page)
|
||||
page += ((address & ~PMD_MASK) >> PAGE_SHIFT);
|
||||
return page;
|
||||
}
|
||||
|
||||
int pmd_huge(pmd_t pmd)
|
||||
{
|
||||
return pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT);
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@
|
|||
#include <asm/system_info.h>
|
||||
|
||||
pgd_t *idmap_pgd;
|
||||
phys_addr_t (*arch_virt_to_idmap) (unsigned long x);
|
||||
|
||||
#ifdef CONFIG_ARM_LPAE
|
||||
static void idmap_add_pmd(pud_t *pud, unsigned long addr, unsigned long end,
|
||||
|
|
@ -24,6 +25,13 @@ static void idmap_add_pmd(pud_t *pud, unsigned long addr, unsigned long end,
|
|||
pr_warning("Failed to allocate identity pmd.\n");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Copy the original PMD to ensure that the PMD entries for
|
||||
* the kernel image are preserved.
|
||||
*/
|
||||
if (!pud_none(*pud))
|
||||
memcpy(pmd, pmd_offset(pud, 0),
|
||||
PTRS_PER_PMD * sizeof(pmd_t));
|
||||
pud_populate(&init_mm, pud, pmd);
|
||||
pmd += pmd_index(addr);
|
||||
} else
|
||||
|
|
@ -67,8 +75,8 @@ static void identity_mapping_add(pgd_t *pgd, const char *text_start,
|
|||
unsigned long addr, end;
|
||||
unsigned long next;
|
||||
|
||||
addr = virt_to_phys(text_start);
|
||||
end = virt_to_phys(text_end);
|
||||
addr = virt_to_idmap(text_start);
|
||||
end = virt_to_idmap(text_end);
|
||||
|
||||
prot |= PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AF;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,13 +4,16 @@ config ARM64
|
|||
select ARCH_USE_CMPXCHG_LOCKREF
|
||||
select ARCH_HAS_OPP
|
||||
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
|
||||
select ARCH_SUPPORTS_ATOMIC_RMW
|
||||
select ARCH_WANT_OPTIONAL_GPIOLIB
|
||||
select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
|
||||
select ARCH_WANT_FRAME_POINTERS
|
||||
select ARM_AMBA
|
||||
select ARM_ARCH_TIMER
|
||||
select ARM_GIC
|
||||
select ARM_GIC_V3
|
||||
select BUILDTIME_EXTABLE_SORT
|
||||
select AUDIT_ARCH_COMPAT_GENERIC
|
||||
select CLONE_BACKWARDS
|
||||
select COMMON_CLK
|
||||
select CPU_PM if (SUSPEND || CPU_IDLE)
|
||||
|
|
@ -29,6 +32,8 @@ config ARM64
|
|||
select HARDIRQS_SW_RESEND
|
||||
select HAVE_ARCH_JUMP_LABEL
|
||||
select HAVE_ARCH_KGDB
|
||||
select HAVE_ARCH_AUDITSYSCALL
|
||||
select HAVE_ARCH_SECCOMP_FILTER
|
||||
select HAVE_ARCH_TRACEHOOK
|
||||
select HAVE_C_RECORDMCOUNT
|
||||
select HAVE_DEBUG_BUGVERBOSE
|
||||
|
|
@ -55,6 +60,7 @@ config ARM64
|
|||
select NO_BOOTMEM
|
||||
select OF
|
||||
select OF_EARLY_FLATTREE
|
||||
select OF_RESERVED_MEM
|
||||
select PERF_USE_VMALLOC
|
||||
select POWER_RESET
|
||||
select POWER_SUPPLY
|
||||
|
|
@ -309,6 +315,31 @@ config HOTPLUG_CPU
|
|||
Say Y here to experiment with turning CPUs off and on. CPUs
|
||||
can be controlled through /sys/devices/system/cpu.
|
||||
|
||||
config SWP_EMULATE
|
||||
bool "Emulate SWP/SWPB instructions"
|
||||
help
|
||||
ARMv6 architecture deprecates use of the SWP/SWPB instructions. ARMv8
|
||||
oblosetes the use of SWP/SWPB instructions. ARMv7 multiprocessing
|
||||
extensions introduce the ability to disable these instructions,
|
||||
triggering an undefined instruction exception when executed. Say Y
|
||||
here to enable software emulation of these instructions for userspace
|
||||
(not kernel) using LDREX/STREX. Also creates /proc/cpu/swp_emulation
|
||||
for statistics.
|
||||
|
||||
In some older versions of glibc [<=2.8] SWP is used during futex
|
||||
trylock() operations with the assumption that the code will not
|
||||
be preempted. This invalid assumption may be more likely to fail
|
||||
with SWP emulation enabled, leading to deadlock of the user
|
||||
application.
|
||||
|
||||
NOTE: when accessing uncached shared regions, LDREX/STREX rely
|
||||
on an external transaction monitoring block called a global
|
||||
monitor to maintain update atomicity. If your system does not
|
||||
implement a global monitor, this option can cause programs that
|
||||
perform SWP operations to uncached memory to deadlock.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
source kernel/Kconfig.preempt
|
||||
|
||||
config HZ
|
||||
|
|
@ -351,6 +382,27 @@ config ARCH_WANT_HUGE_PMD_SHARE
|
|||
config HAVE_ARCH_TRANSPARENT_HUGEPAGE
|
||||
def_bool y
|
||||
|
||||
config ARMV7_COMPAT
|
||||
bool "Kernel support for ARMv7 applications"
|
||||
depends on COMPAT
|
||||
select SWP_EMULATE
|
||||
help
|
||||
This option enables features that allow that ran on an ARMv7 or older
|
||||
processor to continue functioning.
|
||||
|
||||
If you want to execute ARMv7 applications, say Y
|
||||
|
||||
config ARMV7_COMPAT_CPUINFO
|
||||
bool "Report backwards compatible cpu features in /proc/cpuinfo"
|
||||
depends on ARMV7_COMPAT
|
||||
default y
|
||||
help
|
||||
This option makes /proc/cpuinfo list CPU features that an ARMv7 or
|
||||
earlier kernel would report, but are not optional on an ARMv8 or later
|
||||
processor.
|
||||
|
||||
If you want to execute ARMv7 applications, say Y
|
||||
|
||||
source "mm/Kconfig"
|
||||
|
||||
config FORCE_MAX_ZONEORDER
|
||||
|
|
@ -358,6 +410,19 @@ config FORCE_MAX_ZONEORDER
|
|||
default "14" if (ARM64_64K_PAGES && TRANSPARENT_HUGEPAGE)
|
||||
default "11"
|
||||
|
||||
config SECCOMP
|
||||
bool "Enable seccomp to safely compute untrusted bytecode"
|
||||
---help---
|
||||
This kernel feature is useful for number crunching applications
|
||||
that may need to compute untrusted bytecode during their
|
||||
execution. By using pipes or other transports made available to
|
||||
the process as file descriptors supporting the read/write
|
||||
syscalls, it's possible to isolate those applications in
|
||||
their own address space using seccomp. Once seccomp is
|
||||
enabled via prctl(PR_SET_SECCOMP), it cannot be disabled
|
||||
and the task is only allowed to execute a few safe syscalls
|
||||
defined by each seccomp mode.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Boot options"
|
||||
|
|
@ -479,6 +544,8 @@ source "drivers/firmware/Kconfig"
|
|||
|
||||
source "fs/Kconfig"
|
||||
|
||||
source "arch/arm64/kvm/Kconfig"
|
||||
|
||||
source "arch/arm64/Kconfig.debug"
|
||||
|
||||
source "security/Kconfig"
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user