Re: [PATCH v2 2/2] drivers: gpio: add virtio-gpio guest driver
"Enrico Weigelt, metux IT consult" writes: > On 04.12.20 04:35, Jason Wang wrote: > > Hi, > >> Is the plan to keep this doc synced with the one in the virtio >> specification? > > Yes, of course. I'm still in progress of doing the beaurocratic stuff w/ > virtio-tc folks (ID registration, ...) - yet have to see whether they > wanna add it to their spec documents ... > > BTW: if you feel, sometings not good w/ the current spec, please raise > your voice now. > >> I think it's better to use u8 ot uint8_t here.Git grep told me the >> former is more popular under Documentation/. > > thx, I'll fix that > >>> +- for version field currently only value 1 supported. >>> +- the line names block holds a stream of zero-terminated strings, >>> + holding the individual line names. >> >> I'm not sure but does this mean we don't have a fixed length of config >> space? Need to check whether it can bring any trouble to >> migration(compatibility). > > Yes, it depends on how many gpio lines are present and how much space > their names take up. > > A fixed size would either put unpleasent limits on the max number of > lines or waste a lot space when only few lines present. > > Not that virtio-gpio is also meant for small embedded workloads running > under some hypervisor. > >>> +- unspecified fields are reserved for future use and should be zero. >>> + >>> + >>> +Virtqueues and messages: >>> + >>> + >>> +- Queue #0: transmission from host to guest >>> +- Queue #1: transmission from guest to host >> >> >> Virtio became more a popular in the area without virtualization. So I >> think it's better to use "device/driver" instead of "host/guest" here. > > Good point. But I'd prefer "cpu" instead of "driver" in that case. I think you are going to tie yourself up in knots if you don't move this to the OASIS spec. The reason being the VirtIO spec has definitions for what a "Device" and a "Driver" is that are clear and unambiguous. The upstream spec should be considered the canonical source of truth for any implementation (Linux or otherwise). By all means have the distilled documentation for the driver in the kernel source tree but trying to upstream an implementation before starting the definition in the standard is a little back to front IMHO*. * that's not to say these things can't be done in parallel as the spec is reviewed and worked on and the kinks worked out but you want the final order of upstreaming to start with the spec. -- Alex Bennée
Re: [RFC PATCH 1/5] rpmb: add Replay Protected Memory Block (RPMB) subsystem
Hector Martin writes: > On 11/03/2021 23.31, Linus Walleij wrote: >> I understand your argument, is your position such that the nature >> of the hardware is such that community should leave this hardware >> alone and not try to make use of RPMB for say ordinary (self-installed) >> Linux distributions? > > It's not really that the community should leave this hardware alone, so > much that I think there is a very small subset of users who will be able > to benefit from it, and that subset will be happy with a usable > kernel/userspace interface and some userspace tooling for this purpose, > including provisioning and such. > > Consider the prerequisites for using RPMB usefully here: > > * You need (user-controlled) secureboot > * You need secret key storage - so either some kind of CPU-fused key, or > one protected by a TPM paired with the secureboot (key sealed to PCR > values and such) > * But if you have a TPM, that can handle secure counters for you already > AIUI, so you don't need RPMB > * So this means you must be running a non-TPM secureboot system > > And so we're back to embedded platforms like Android phones and other > SoC stuff... user-controlled secureboot is already somewhat rare here, > and even rarer are the cases where the user controls the whole chain > including the TEE if any (otherwise it'll be using RPMB already); this > pretty much excludes all production Android phones except for a few > designed as completely open systems; we're left with those and a subset > of dev boards (e.g. the Jetson TX1 I did fuse experiments on). In the > end, those systems will probably end up with fairly bespoke set-ups for > any given device or SoC family, for using RPMB. > > But then again, if you have a full secureboot system where you control > the TEE level, wouldn't you want to put the RPMB shenanigans there and > get some semblance of secure TPM/keystore/attempt throttling > functionality that is robust against Linux exploits and has a smaller > attack surface? Systems without EL3 are rare (Apple M1 :-)) so it makes > more sense to do this on those that do have it. If you're paranoid > enough to be getting into building your own secure system with > anti-rollback for retry counters, you should be heading in that directly > anyway. > > And now Linux's RPMB code is useless because you're running the stack in > the secure monitor instead :-) Well quiet - the principle use-case of virtio-rpmb is to provide a RPMB like device emulation for things like OPTEE when running under QEMU's full-system emulation. However when it came to testing it out I went for Thomas' patches because that was the only virtio FE implementation available. When I finished the implementation and Ilias started on the uBoot front-end for virtio-rpmb. uBoot being firmware could very well be running in the secure world so would have a valid use case accessing an RPMB device. We ran into API dissonance because uboot's driver model is roughly modelled on the kernel so expects to be talking to eMMC devices which lead to requirements to fake something up to keep the driver stacks happy. I guess what we are saying is that real secure monitors should come up with their own common API for interfacing with RPMB devices without looking to the Linux kernel for inspiration? -- Alex Bennée
Re: [RFC PATCH 0/5] RPMB internal and user-space API + WIP virtio-rpmb frontend
Avri Altman writes: > The mmc driver has some hooks to support rpmb access, but access is > mainly facilitated from user space, e.g. mmc-utils. > > The ufs driver has no concept of rpmb access - it is facilitated via > user space, e.g. ufs-utils and similar. > > Both for ufs and mmc, rpmb access is defined in their applicable jedec > specs. This is the case for few years now - AFAIK No new rpmb-related > stuff is expected to be introduced in the near future. > > What problems, as far as mmc and ufs, are you trying to solve by this > new subsystem? Well in my case the addition of virtio-rpmb. As yet another RPMB device which only supports RPMB transactions and isn't part of a wider block device. The API dissonance comes into play when looking to implement it as part of wider block device stacks and then having to do things like fake 0 length eMMC devices with just an RPMB partition to use existing tools. I guess that was the original attraction of having a common kernel subsystem to interact with RPMB functionality regardless of the underlying HW. However from the other comments it seems the preference is just to leave it to user-space and domain specific tools for each device type. > > Thanks, > Avri -- Alex Bennée
Re: [RFC PATCH 2/5] char: rpmb: provide a user space interface
Winkler, Tomas writes: >> "Winkler, Tomas" writes: >> >> >> The user space API is achieved via a number of synchronous IOCTLs. >> >> >> >> * RPMB_IOC_VER_CMD - simple versioning API >> >> * RPMB_IOC_CAP_CMD - query of underlying capabilities >> >> * RPMB_IOC_PKEY_CMD - one time programming of access key >> >> * RPMB_IOC_COUNTER_CMD - query the write counter >> >> * RPMB_IOC_WBLOCKS_CMD - write blocks to device >> >> * RPMB_IOC_RBLOCKS_CMD - read blocks from device >> >> >> >> The keys used for programming and writing blocks to the device are >> >> key_serial_t handles as provided by the keyctl() interface. >> >> >> >> [AJB: here there are two key differences between this and the >> >> original proposal. The first is the dropping of the sequence of >> >> preformated frames in favour of explicit actions. The second is the >> >> introduction of key_serial_t and the keyring API for referencing the >> >> key to use] >> > >> > Putting it gently I'm not sure this is good idea, from the security point >> > of >> view. >> > The key has to be possession of the one that signs the frames as they are, >> it doesn't mean it is linux kernel keyring, it can be other party on >> different >> system. >> > With this approach you will make the other usecases not applicable. It >> > is less then trivial to move key securely from one system to another. >> >> OK I can understand the desire for such a use-case but it does constrain the >> interface on the kernel with access to the hardware to purely providing a >> pipe to the raw hardware while also having to expose the details of the HW >> to userspace. > This is the use case in Android. The key is in the "trusty" which > different os running in a virtual environment. The file storage > abstraction is implemented there. I'm not sure the point of > constraining the kernel, can you please elaborate on that. Well the kernel is all about abstracting differences not baking in assumptions. However can I ask a bit more about this security model? Is the secure enclave just a separate userspace process or is it in a separate virtual machine? Is it accessible at all by the kernel running the driver? The fact that key id is passed down into the kernel doesn't have to imply the kernel does the final cryptographic operation. In the ARM world you could make a call to the secure world to do the operation for you. I note the keyctl() interface already has support for going to userspace to make queries of the keyring. Maybe what is really needed is an abstraction for the kernel to delegate the MAC calculation to some other trusted process that also understands the keyid. > > Also doesn't this break down after a PROGRAM_KEY event as >> the key will have had to traverse into the "untrusted" kernel? > > This is one in a life event of the card happening on the manufacturing > floor, maybe even not performed on Linux. In an off list conversation it was suggested that maybe the PROGRAM_KEY ioctl should be disabled for locked down kernels to dissuade production use of the facility (it is handy for testing though!). >> I wonder if virtio-rpmb may be of help here? You could wrap up up the front- >> end in the security domain that has the keys although I don't know how easy >> it would be for a backend to work with real hardware? > > I'm open to see any proposal, not sure I can wrap may head about it right > now. > > Anyway I was about to send the new round of my code, but let's come to > common ground first. > OK - I'll see what the others say. -- Alex Bennée
Re: [RFC PATCH 2/5] char: rpmb: provide a user space interface
"Winkler, Tomas" writes: >> The user space API is achieved via a number of synchronous IOCTLs. >> >> * RPMB_IOC_VER_CMD - simple versioning API >> * RPMB_IOC_CAP_CMD - query of underlying capabilities >> * RPMB_IOC_PKEY_CMD - one time programming of access key >> * RPMB_IOC_COUNTER_CMD - query the write counter >> * RPMB_IOC_WBLOCKS_CMD - write blocks to device >> * RPMB_IOC_RBLOCKS_CMD - read blocks from device >> >> The keys used for programming and writing blocks to the device are >> key_serial_t handles as provided by the keyctl() interface. >> >> [AJB: here there are two key differences between this and the original >> proposal. The first is the dropping of the sequence of preformated frames in >> favour of explicit actions. The second is the introduction of key_serial_t >> and >> the keyring API for referencing the key to use] > > Putting it gently I'm not sure this is good idea, from the security point of > view. > The key has to be possession of the one that signs the frames as they are, it > doesn't mean it is linux kernel keyring, it can be other party on different > system. > With this approach you will make the other usecases not applicable. It > is less then trivial to move key securely from one system to another. OK I can understand the desire for such a use-case but it does constrain the interface on the kernel with access to the hardware to purely providing a pipe to the raw hardware while also having to expose the details of the HW to userspace. Also doesn't this break down after a PROGRAM_KEY event as the key will have had to traverse into the "untrusted" kernel? I wonder if virtio-rpmb may be of help here? You could wrap up up the front-end in the security domain that has the keys although I don't know how easy it would be for a backend to work with real hardware? > We all wished it can be abstracted more but the frames has to come already > signed, and the key material is inside the frame. > Thanks > Tomas > > >> >> Signed-off-by: Alex Bennée >> Cc: Ulf Hansson >> Cc: Linus Walleij >> Cc: Arnd Bergmann >> Cc: Ilias Apalodimas >> Cc: Tomas Winkler >> Cc: Alexander Usyskin >> Cc: Avri Altman >> --- >> .../userspace-api/ioctl/ioctl-number.rst | 1 + >> MAINTAINERS | 1 + >> drivers/char/rpmb/Kconfig | 7 + >> drivers/char/rpmb/Makefile| 1 + >> drivers/char/rpmb/cdev.c | 246 ++ >> drivers/char/rpmb/core.c | 10 +- >> drivers/char/rpmb/rpmb-cdev.h | 17 ++ >> include/linux/rpmb.h | 10 + >> include/uapi/linux/rpmb.h | 68 + >> 9 files changed, 357 insertions(+), 4 deletions(-) create mode 100644 >> drivers/char/rpmb/cdev.c create mode 100644 drivers/char/rpmb/rpmb- >> cdev.h create mode 100644 include/uapi/linux/rpmb.h >> >> diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst >> b/Documentation/userspace-api/ioctl/ioctl-number.rst >> index a4c75a28c839..0ff2d4d81bb0 100644 >> --- a/Documentation/userspace-api/ioctl/ioctl-number.rst >> +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst >> @@ -344,6 +344,7 @@ Code Seq#Include File >> Comments >> 0xB5 00-0F uapi/linux/rpmsg.h >> <mailto:linux- >> remotep...@vger.kernel.org> >> 0xB6 alllinux/fpga-dfl.h >> 0xB7 alluapi/linux/remoteproc_cdev.h >> <mailto:linux- >> remotep...@vger.kernel.org> >> +0xB8 80-8F uapi/linux/rpmb.h >> <mailto:linux- >> m...@vger.kernel.org> >> 0xC0 00-0F linux/usb/iowarrior.h >> 0xCA 00-0F uapi/misc/cxl.h >> 0xCA 10-2F uapi/misc/ocxl.h >> diff --git a/MAINTAINERS b/MAINTAINERS >> index 076f3983526c..c60b41b6e6bd 100644 >> --- a/MAINTAINERS >> +++ b/MAINTAINERS >> @@ -15374,6 +15374,7 @@ M: ? >> L: linux-kernel@vger.kernel.org >> S: Supported >> F: drivers/char/rpmb/* >> +F: include/uapi/linux/rpmb.h >> F: include/linux/rpmb.h >> >> RTL2830 MEDIA DRIVER >> diff --git a/drivers/char/rpmb/Kconfig b/drivers/char/rpmb/Kconfig index >> 431c2823cf70..9068664a399a 100644 >> --- a/drivers/char/rpmb/Kconfig >> +++ b/drivers/char/rpmb/Kconfig >> @@ -9,3 +9,10 @@ config RPMB >>access RPMB partition. >> >>If unsure, select N.
Re: [RFC PATCH 1/5] rpmb: add Replay Protected Memory Block (RPMB) subsystem
Foolishly I'd missed you out of the series Cc so you only got those two patches. You should find the rest @ Subject: [RFC PATCH 0/5] RPMB internal and user-space API + WIP virtio-rpmb frontend Date: Wed, 3 Mar 2021 13:54:55 + Message-Id: <20210303135500.24673-1-alex.ben...@linaro.org> assuming you are subscribed to one of the Cc'd lists. On Wed, 3 Mar 2021 at 15:29, Ulf Hansson wrote: > > On Wed, 3 Mar 2021 at 14:55, Alex Bennée wrote: > > > > A number of storage technologies support a specialised hardware > > partition designed to be resistant to replay attacks. The underlying > > HW protocols differ but the operations are common. The RPMB partition > > cannot be accessed via standard block layer, but by a set of specific > > commands: WRITE, READ, GET_WRITE_COUNTER, and PROGRAM_KEY. Such a > > partition provides authenticated and replay protected access, hence > > suitable as a secure storage. > > > > The RPMB layer aims to provide in-kernel API for Trusted Execution > > Environment (TEE) devices that are capable to securely compute block > > frame signature. In case a TEE device wishes to store a replay > > protected data, requests the storage device via RPMB layer to store > > the data. > > > > A TEE device driver can claim the RPMB interface, for example, via > > class_interface_register(). The RPMB layer provides a series of > > operations for interacting with the device. > > > > * program_key - a one time operation for setting up a new device > > * get_capacity - introspect the device capacity > > * get_write_count - check the write counter > > * write_blocks - write a series of blocks to the RPMB device > > * read_blocks - read a series of blocks from the RPMB device > > > > The detailed operation of implementing the access is left to the TEE > > device driver itself. > > > > [This is based-on Thomas Winkler's proposed API from: > > > > > > https://lore.kernel.org/linux-mmc/1478548394-8184-2-git-send-email-tomas.wink...@intel.com/ > > > > The principle difference is the framing details and HW specific > > bits (JDEC vs NVME frames) are left to the lower level TEE driver to > > worry about. The eventual userspace ioctl interface will aim to be > > similarly generic. This is an RFC to follow up on: > > > > Subject: RPMB user space ABI > > Date: Thu, 11 Feb 2021 14:07:00 + > > Message-ID: <87mtwashi4@linaro.org>] > > > > Signed-off-by: Alex Bennée > > Cc: Tomas Winkler > > Cc: Ulf Hansson > > Cc: Linus Walleij > > Cc: Arnd Bergmann > > Cc: Ilias Apalodimas > > Alex, I promise to have a closer look at this and provide my opinions. > > However, it looks like you have posted patch 1 and patch2, but the > remainder 3, 4, 5 I can't find. Was this perhaps intentional? > > Moreover, I think these kinds of changes deserve a proper > cover-letter, describing the overall goal with the series. Can you > perhaps re-submit, so clarify things. > > Kind regards > Uffe > > > --- > > MAINTAINERS| 7 + > > drivers/char/Kconfig | 2 + > > drivers/char/Makefile | 1 + > > drivers/char/rpmb/Kconfig | 11 + > > drivers/char/rpmb/Makefile | 7 + > > drivers/char/rpmb/core.c | 429 + > > include/linux/rpmb.h | 163 ++ > > 7 files changed, 620 insertions(+) > > create mode 100644 drivers/char/rpmb/Kconfig > > create mode 100644 drivers/char/rpmb/Makefile > > create mode 100644 drivers/char/rpmb/core.c > > create mode 100644 include/linux/rpmb.h > > > > diff --git a/MAINTAINERS b/MAINTAINERS > > index bfc1b86e3e73..076f3983526c 100644 > > --- a/MAINTAINERS > > +++ b/MAINTAINERS > > @@ -15369,6 +15369,13 @@ T: git git://linuxtv.org/media_tree.git > > F: > > Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-de2-rotate.yaml > > F: drivers/media/platform/sunxi/sun8i-rotate/ > > > > +RPMB SUBSYSTEM > > +M: ? > > +L: linux-kernel@vger.kernel.org > > +S: Supported > > +F: drivers/char/rpmb/* > > +F: include/linux/rpmb.h > > + > > RTL2830 MEDIA DRIVER > > M: Antti Palosaari > > L: linux-me...@vger.kernel.org > > diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig > > index d229a2d0c017..a7834cc3e0ea 100644 > > --- a/drivers/char/Kconfig > > +++ b/drivers/char/Kconfig > > @@ -471,6 +471,8 @@ config ADI > > and SSM (Silicon
[RFC PATCH 4/5] rpmb: create virtio rpmb frontend driver [WIP]
This implements a virtio rpmb frontend driver for the RPMB subsystem. [AJB: the principle difference is all the MAC calculation and validation is now done in the driver] Signed-off-by: Alex Bennée Cc: Tomas Winkler --- ajb: - add include linux/slab.h for kzalloc - include standardised VIRTIO_ID_RPMB - remove extra frames when sending commands down virtqueue - clean up out/in sgs - hopefully more conforming - remove cmd_cap code --- drivers/char/rpmb/Kconfig| 10 + drivers/char/rpmb/Makefile | 1 + drivers/char/rpmb/virtio_rpmb.c | 366 +++ include/uapi/linux/virtio_ids.h | 1 + include/uapi/linux/virtio_rpmb.h | 54 + 5 files changed, 432 insertions(+) create mode 100644 drivers/char/rpmb/virtio_rpmb.c create mode 100644 include/uapi/linux/virtio_rpmb.h diff --git a/drivers/char/rpmb/Kconfig b/drivers/char/rpmb/Kconfig index 9068664a399a..845f458452a5 100644 --- a/drivers/char/rpmb/Kconfig +++ b/drivers/char/rpmb/Kconfig @@ -16,3 +16,13 @@ config RPMB_INTF_DEV help Say yes here if you want to access RPMB from user space via character device interface /dev/rpmb%d + +config VIRTIO_RPMB + tristate "Virtio RPMB character device interface /dev/vrpmb" + default n + depends on VIRTIO && KEYS + select RPMB + help + Say yes here if you want to access virtio RPMB from user space + via character device interface /dev/vrpmb. + This device interface is only for guest/frontend virtio driver. diff --git a/drivers/char/rpmb/Makefile b/drivers/char/rpmb/Makefile index f54b3f30514b..4b397b50a42c 100644 --- a/drivers/char/rpmb/Makefile +++ b/drivers/char/rpmb/Makefile @@ -4,5 +4,6 @@ obj-$(CONFIG_RPMB) += rpmb.o rpmb-objs += core.o rpmb-$(CONFIG_RPMB_INTF_DEV) += cdev.o +obj-$(CONFIG_VIRTIO_RPMB) += virtio_rpmb.o ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/char/rpmb/virtio_rpmb.c b/drivers/char/rpmb/virtio_rpmb.c new file mode 100644 index ..6ade26874a4e --- /dev/null +++ b/drivers/char/rpmb/virtio_rpmb.c @@ -0,0 +1,366 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Virtio RPMB Front End Driver + * + * Copyright (c) 2018-2019 Intel Corporation. + * Copyright (c) 2021 Linaro Ltd. + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RPMB_MAC_SIZE 32 + +static const char id[] = "RPMB:VIRTIO"; + +struct virtio_rpmb_info { + struct virtqueue *vq; + struct mutex lock; /* info lock */ + wait_queue_head_t have_data; + struct rpmb_dev *rdev; +}; + +static void virtio_rpmb_recv_done(struct virtqueue *vq) +{ + struct virtio_rpmb_info *vi; + struct virtio_device *vdev = vq->vdev; + + vi = vq->vdev->priv; + if (!vi) { + dev_err(&vdev->dev, "Error: no found vi data.\n"); + return; + } + + wake_up(&vi->have_data); +} + +/* static int rpmb_virtio_cmd_seq(struct device *dev, u8 target, */ +/*struct rpmb_cmd *cmds, u32 ncmds) */ +/* { */ +/* struct virtio_device *vdev = dev_to_virtio(dev); */ +/* struct virtio_rpmb_info *vi = vdev->priv; */ +/* unsigned int i; */ +/* struct scatterlist out_frames[3]; */ +/* struct scatterlist in_frames[3]; */ +/* struct scatterlist *sgs[3]; */ +/* unsigned int num_out = 0, num_in = 0; */ +/* size_t sz; */ +/* int ret; */ +/* unsigned int len; */ + +/* if (ncmds > RPMB_SEQ_CMD_MAX) */ +/* return -EINVAL; */ + +/* mutex_lock(&vi->lock); */ + +/* /\* */ +/* * Process the frames - putting in the appropriate out_frames */ +/* * and in_frames before we build our final ordered sgs[] out */ +/* * array. */ +/* *\/ */ +/* for (i = 0; i < ncmds; i++) { */ +/* struct rpmb_cmd *cmd = &cmds[i]; */ +/* sz = sizeof(struct rpmb_frame_jdec) * (cmd->nframes ?: 1); */ +/* if (cmd->flags) { */ +/* sg_init_one(&out_frames[num_out++], cmd->frames, sz); */ +/* } else { */ +/* sg_init_one(&in_frames[num_in++], cmd->frames, sz); */ +/* } */ +/* } */ + +/* for (i = 0; i < num_out; i++) { */ +/* sgs[i] = &out_frames[i]; */ +/* } */ +/* for (i = 0; i < num_in; i++) { */ +/* sgs[num_out + i] = &in_frames[i]; */ +/* } */ + +/* dev_warn(dev, "out = %d, in = %d\n", num_out, num_in); */ + +/* virtqueue_add_sgs(vi->vq, sgs, num_out, num_in, vi, GFP_KERNEL); */ +/* virtqueue_kick(vi->vq); */ + +/* wait_event(vi->have_data, virtqueue_get_buf(vi->vq, &len)); */ + +/* ret = 0; */ + +/* /\
[RFC PATCH 0/5] RPMB internal and user-space API + WIP virtio-rpmb frontend
Hi, This is a follow-up to the email I sent last month: Subject: RPMB user space ABI Date: Thu, 11 Feb 2021 14:07:00 + Message-ID: <87mtwashi4@linaro.org> which attempts to put some concrete flesh on the bones of the proposal for a new internal kernel API for dealing with RPMB partitions and the resultant exposed user-space character device API. It became apparent while implementing a virtio-rpmb backend that the initial proposed API didn't sit well with a device like virtio-rpmb which isn't part of a greater device (like eMMC or UFS). It also exposed the gritty details of the frame format to userspace leaving it to deal with the complications of creating JDEC frames and calculating MACs. The series is based on Thomas' last posting with a bunch of functionality dropped: - no FS/RPMB integration - dropped the simulator - dropped the sysfs patches There is a start of a WIP virtio-rpmb front-end however as the initial discussion should be focused on the proposed APIs I thought it would be worth posting as an RFC before getting too deep into the weeds of implementation. The principle changes to the original proposal: - frame construction left to device driver The differences between UFS/JEDEC/VirtioRPMB are left for the driver itself to deal with. This means things like MAC calculation and validation also remain the preserve of the low level implementation details. This doesn't mean there can't be shared code where implementation details are common across several device types. - key management uses keyctl() This means in theory userspace could interact with the RPMB device without having to manage the key itself. This also means you don't need to pass as much data about as the kernel internals can just use the keyring id with the API to fetch the key when required. - user-space interface split across several ioctls Now we no longer have multiple command frames going back and forth we can have a single structure per ioctl which just contains what is needed for the operation in question. So what do people think? Is it worth pursuing this approach? I'm certainly intended to complete the virtio-rpmb driver and test it with my QEMU based vhost-user backend. However I've no direct interest in implementing the interfaces to real hardware. I leave that to people who have access to such things and are willing to take up the maintainer burden if this is merged. Alex Bennée (5): rpmb: add Replay Protected Memory Block (RPMB) subsystem char: rpmb: provide a user space interface tools rpmb: add RPBM access tool rpmb: create virtio rpmb frontend driver [WIP] tools/rpmb: simple test sequence .../userspace-api/ioctl/ioctl-number.rst | 1 + MAINTAINERS | 9 + drivers/char/Kconfig | 2 + drivers/char/Makefile | 1 + drivers/char/rpmb/Kconfig | 28 + drivers/char/rpmb/Makefile| 9 + drivers/char/rpmb/cdev.c | 246 +++ drivers/char/rpmb/core.c | 431 drivers/char/rpmb/rpmb-cdev.h | 17 + drivers/char/rpmb/virtio_rpmb.c | 366 ++ include/linux/rpmb.h | 173 + include/uapi/linux/rpmb.h | 68 ++ include/uapi/linux/virtio_ids.h | 1 + include/uapi/linux/virtio_rpmb.h | 54 ++ tools/Makefile| 14 +- tools/rpmb/.gitignore | 2 + tools/rpmb/Makefile | 41 ++ tools/rpmb/key| 1 + tools/rpmb/rpmb.c | 649 ++ tools/rpmb/test.sh| 13 + 20 files changed, 2121 insertions(+), 5 deletions(-) create mode 100644 drivers/char/rpmb/Kconfig create mode 100644 drivers/char/rpmb/Makefile create mode 100644 drivers/char/rpmb/cdev.c create mode 100644 drivers/char/rpmb/core.c create mode 100644 drivers/char/rpmb/rpmb-cdev.h create mode 100644 drivers/char/rpmb/virtio_rpmb.c create mode 100644 include/linux/rpmb.h create mode 100644 include/uapi/linux/rpmb.h create mode 100644 include/uapi/linux/virtio_rpmb.h create mode 100644 tools/rpmb/.gitignore create mode 100644 tools/rpmb/Makefile create mode 100644 tools/rpmb/key create mode 100644 tools/rpmb/rpmb.c create mode 100755 tools/rpmb/test.sh -- 2.20.1
[RFC PATCH 1/5] rpmb: add Replay Protected Memory Block (RPMB) subsystem
A number of storage technologies support a specialised hardware partition designed to be resistant to replay attacks. The underlying HW protocols differ but the operations are common. The RPMB partition cannot be accessed via standard block layer, but by a set of specific commands: WRITE, READ, GET_WRITE_COUNTER, and PROGRAM_KEY. Such a partition provides authenticated and replay protected access, hence suitable as a secure storage. The RPMB layer aims to provide in-kernel API for Trusted Execution Environment (TEE) devices that are capable to securely compute block frame signature. In case a TEE device wishes to store a replay protected data, requests the storage device via RPMB layer to store the data. A TEE device driver can claim the RPMB interface, for example, via class_interface_register(). The RPMB layer provides a series of operations for interacting with the device. * program_key - a one time operation for setting up a new device * get_capacity - introspect the device capacity * get_write_count - check the write counter * write_blocks - write a series of blocks to the RPMB device * read_blocks - read a series of blocks from the RPMB device The detailed operation of implementing the access is left to the TEE device driver itself. [This is based-on Thomas Winkler's proposed API from: https://lore.kernel.org/linux-mmc/1478548394-8184-2-git-send-email-tomas.wink...@intel.com/ The principle difference is the framing details and HW specific bits (JDEC vs NVME frames) are left to the lower level TEE driver to worry about. The eventual userspace ioctl interface will aim to be similarly generic. This is an RFC to follow up on: Subject: RPMB user space ABI Date: Thu, 11 Feb 2021 14:07:00 + Message-ID: <87mtwashi4@linaro.org>] Signed-off-by: Alex Bennée Cc: Tomas Winkler Cc: Ulf Hansson Cc: Linus Walleij Cc: Arnd Bergmann Cc: Ilias Apalodimas --- MAINTAINERS| 7 + drivers/char/Kconfig | 2 + drivers/char/Makefile | 1 + drivers/char/rpmb/Kconfig | 11 + drivers/char/rpmb/Makefile | 7 + drivers/char/rpmb/core.c | 429 + include/linux/rpmb.h | 163 ++ 7 files changed, 620 insertions(+) create mode 100644 drivers/char/rpmb/Kconfig create mode 100644 drivers/char/rpmb/Makefile create mode 100644 drivers/char/rpmb/core.c create mode 100644 include/linux/rpmb.h diff --git a/MAINTAINERS b/MAINTAINERS index bfc1b86e3e73..076f3983526c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15369,6 +15369,13 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-de2-rotate.yaml F: drivers/media/platform/sunxi/sun8i-rotate/ +RPMB SUBSYSTEM +M: ? +L: linux-kernel@vger.kernel.org +S: Supported +F: drivers/char/rpmb/* +F: include/linux/rpmb.h + RTL2830 MEDIA DRIVER M: Antti Palosaari L: linux-me...@vger.kernel.org diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index d229a2d0c017..a7834cc3e0ea 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -471,6 +471,8 @@ config ADI and SSM (Silicon Secured Memory). Intended consumers of this driver include crash and makedumpfile. +source "drivers/char/rpmb/Kconfig" + endmenu config RANDOM_TRUST_CPU diff --git a/drivers/char/Makefile b/drivers/char/Makefile index ffce287ef415..0eed6e21a7a7 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -47,3 +47,4 @@ obj-$(CONFIG_PS3_FLASH) += ps3flash.o obj-$(CONFIG_XILLYBUS) += xillybus/ obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o obj-$(CONFIG_ADI) += adi.o +obj-$(CONFIG_RPMB) += rpmb/ diff --git a/drivers/char/rpmb/Kconfig b/drivers/char/rpmb/Kconfig new file mode 100644 index ..431c2823cf70 --- /dev/null +++ b/drivers/char/rpmb/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2015-2019, Intel Corporation. + +config RPMB + tristate "RPMB partition interface" + help + Unified RPMB partition interface for eMMC and UFS. + Provides interface for in kernel security controllers to + access RPMB partition. + + If unsure, select N. diff --git a/drivers/char/rpmb/Makefile b/drivers/char/rpmb/Makefile new file mode 100644 index ..24d4752a9a53 --- /dev/null +++ b/drivers/char/rpmb/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2015-2019, Intel Corporation. + +obj-$(CONFIG_RPMB) += rpmb.o +rpmb-objs += core.o + +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/char/rpmb/core.c b/drivers/char/rpmb/core.c new file mode 100644 index ..a2e21c14986a --- /dev/null +++ b/drivers/char/rpmb/core.c @@ -0,0 +1,429 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(c) 2015 - 2019 Intel Corporation. All rights reserved. + *
[RFC PATCH 2/5] char: rpmb: provide a user space interface
The user space API is achieved via a number of synchronous IOCTLs. * RPMB_IOC_VER_CMD - simple versioning API * RPMB_IOC_CAP_CMD - query of underlying capabilities * RPMB_IOC_PKEY_CMD - one time programming of access key * RPMB_IOC_COUNTER_CMD - query the write counter * RPMB_IOC_WBLOCKS_CMD - write blocks to device * RPMB_IOC_RBLOCKS_CMD - read blocks from device The keys used for programming and writing blocks to the device are key_serial_t handles as provided by the keyctl() interface. [AJB: here there are two key differences between this and the original proposal. The first is the dropping of the sequence of preformated frames in favour of explicit actions. The second is the introduction of key_serial_t and the keyring API for referencing the key to use] Signed-off-by: Alex Bennée Cc: Ulf Hansson Cc: Linus Walleij Cc: Arnd Bergmann Cc: Ilias Apalodimas Cc: Tomas Winkler Cc: Alexander Usyskin Cc: Avri Altman --- .../userspace-api/ioctl/ioctl-number.rst | 1 + MAINTAINERS | 1 + drivers/char/rpmb/Kconfig | 7 + drivers/char/rpmb/Makefile| 1 + drivers/char/rpmb/cdev.c | 246 ++ drivers/char/rpmb/core.c | 10 +- drivers/char/rpmb/rpmb-cdev.h | 17 ++ include/linux/rpmb.h | 10 + include/uapi/linux/rpmb.h | 68 + 9 files changed, 357 insertions(+), 4 deletions(-) create mode 100644 drivers/char/rpmb/cdev.c create mode 100644 drivers/char/rpmb/rpmb-cdev.h create mode 100644 include/uapi/linux/rpmb.h diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst index a4c75a28c839..0ff2d4d81bb0 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -344,6 +344,7 @@ Code Seq#Include File Comments 0xB5 00-0F uapi/linux/rpmsg.h <mailto:linux-remotep...@vger.kernel.org> 0xB6 alllinux/fpga-dfl.h 0xB7 alluapi/linux/remoteproc_cdev.h <mailto:linux-remotep...@vger.kernel.org> +0xB8 80-8F uapi/linux/rpmb.h <mailto:linux-...@vger.kernel.org> 0xC0 00-0F linux/usb/iowarrior.h 0xCA 00-0F uapi/misc/cxl.h 0xCA 10-2F uapi/misc/ocxl.h diff --git a/MAINTAINERS b/MAINTAINERS index 076f3983526c..c60b41b6e6bd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15374,6 +15374,7 @@ M: ? L: linux-kernel@vger.kernel.org S: Supported F: drivers/char/rpmb/* +F: include/uapi/linux/rpmb.h F: include/linux/rpmb.h RTL2830 MEDIA DRIVER diff --git a/drivers/char/rpmb/Kconfig b/drivers/char/rpmb/Kconfig index 431c2823cf70..9068664a399a 100644 --- a/drivers/char/rpmb/Kconfig +++ b/drivers/char/rpmb/Kconfig @@ -9,3 +9,10 @@ config RPMB access RPMB partition. If unsure, select N. + +config RPMB_INTF_DEV + bool "RPMB character device interface /dev/rpmbN" + depends on RPMB && KEYS + help + Say yes here if you want to access RPMB from user space + via character device interface /dev/rpmb%d diff --git a/drivers/char/rpmb/Makefile b/drivers/char/rpmb/Makefile index 24d4752a9a53..f54b3f30514b 100644 --- a/drivers/char/rpmb/Makefile +++ b/drivers/char/rpmb/Makefile @@ -3,5 +3,6 @@ obj-$(CONFIG_RPMB) += rpmb.o rpmb-objs += core.o +rpmb-$(CONFIG_RPMB_INTF_DEV) += cdev.o ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/char/rpmb/cdev.c b/drivers/char/rpmb/cdev.c new file mode 100644 index ..55f66720fd03 --- /dev/null +++ b/drivers/char/rpmb/cdev.c @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(c) 2015 - 2019 Intel Corporation. + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include + +#include + +#include "rpmb-cdev.h" + +static dev_t rpmb_devt; +#define RPMB_MAX_DEVS MINORMASK + +#define RPMB_DEV_OPEN0 /** single open bit (position) */ + +/** + * rpmb_open - the open function + * + * @inode: pointer to inode structure + * @fp: pointer to file structure + * + * Return: 0 on success, <0 on error + */ +static int rpmb_open(struct inode *inode, struct file *fp) +{ + struct rpmb_dev *rdev; + + rdev = container_of(inode->i_cdev, struct rpmb_dev, cdev); + if (!rdev) + return -ENODEV; + + /* the rpmb is single open! */ + if (test_and_set_bit(RPMB_DEV_OPEN, &rdev->status)) + return -EBUSY; + + mutex_lock(&rdev->lock); + + fp->private_data = rdev; + + mutex_unlock(&rdev->lock); + + return nonseekable_open(inode, fp); +} + +/** + * rpmb_release - the cdev release
[RFC PATCH 5/5] tools/rpmb: simple test sequence
A simple test script to exercise the rpmb interface. Signed-off-by: Alex Bennée --- tools/rpmb/key | 1 + tools/rpmb/test.sh | 13 + 2 files changed, 14 insertions(+) create mode 100644 tools/rpmb/key create mode 100755 tools/rpmb/test.sh diff --git a/tools/rpmb/key b/tools/rpmb/key new file mode 100644 index ..2b6bd3bc3fe6 --- /dev/null +++ b/tools/rpmb/key @@ -0,0 +1 @@ +h�#ע�pRT��\r|O� �mo� \ No newline at end of file diff --git a/tools/rpmb/test.sh b/tools/rpmb/test.sh new file mode 100755 index ..ae5ce49a412f --- /dev/null +++ b/tools/rpmb/test.sh @@ -0,0 +1,13 @@ +#!/bin/sh -e +echo "get info" +./rpmb -v get-info /dev/rpmb0 +echo "program key" +./rpmb -v program-key /dev/rpmb0 key +echo "get write counter" +./rpmb -v write-counter /dev/rpmb0 +echo "generating data" +dd if=/dev/urandom of=data.in count=1 bs=256 +echo "write data" +./rpmb -v write-blocks /dev/rpmb0 0 1 data.in +echo "read data back" +./rpmb -v read-blocks /dev/rpmb0 0 1 data.out -- 2.20.1
[RFC PATCH 3/5] tools rpmb: add RPBM access tool
Add simple RPMB host testing tool. It can be used to program key, write and read data block, and retrieve write counter. [AJB: the principle differences are a simpler ioctl API which doesn't need to do the low level frame construction itself. It also uses the kernel keychain API for managing the keys] Signed-off-by: Alex Bennée Cc: Tomas Winkler Cc: Alexander Usyskin --- MAINTAINERS | 1 + tools/Makefile| 14 +- tools/rpmb/.gitignore | 2 + tools/rpmb/Makefile | 41 +++ tools/rpmb/rpmb.c | 649 ++ 5 files changed, 702 insertions(+), 5 deletions(-) create mode 100644 tools/rpmb/.gitignore create mode 100644 tools/rpmb/Makefile create mode 100644 tools/rpmb/rpmb.c diff --git a/MAINTAINERS b/MAINTAINERS index c60b41b6e6bd..8b0768b16eae 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15376,6 +15376,7 @@ S: Supported F: drivers/char/rpmb/* F: include/uapi/linux/rpmb.h F: include/linux/rpmb.h +F: tools/rpmb/ RTL2830 MEDIA DRIVER M: Antti Palosaari diff --git a/tools/Makefile b/tools/Makefile index 85af6ebbce91..916ab8f8cefc 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -27,6 +27,7 @@ help: @echo ' objtool- an ELF object analysis tool' @echo ' pci- PCI tools' @echo ' perf - Linux performance measurement and analysis tool' + @echo ' rpmb - Replay protected memory block access tool' @echo ' selftests - various kernel selftests' @echo ' bootconfig - boot config tool' @echo ' spi- spi tools' @@ -64,7 +65,7 @@ acpi: FORCE cpupower: FORCE $(call descend,power/$@) -cgroup firewire hv guest bootconfig spi usb virtio vm bpf iio gpio objtool leds wmi pci firmware debugging: FORCE +cgroup firewire hv guest bootconfig rpmb spi usb virtio vm bpf iio gpio objtool leds wmi pci firmware debugging: FORCE $(call descend,$@) bpf/%: FORCE @@ -100,7 +101,7 @@ kvm_stat: FORCE $(call descend,kvm/$@) all: acpi cgroup cpupower gpio hv firewire liblockdep \ - perf selftests bootconfig spi turbostat usb \ + perf rpmb selftests bootconfig spi turbostat usb \ virtio vm bpf x86_energy_perf_policy \ tmon freefall iio objtool kvm_stat wmi \ pci debugging @@ -111,7 +112,7 @@ acpi_install: cpupower_install: $(call descend,power/$(@:_install=),install) -cgroup_install firewire_install gpio_install hv_install iio_install perf_install bootconfig_install spi_install usb_install virtio_install vm_install bpf_install objtool_install wmi_install pci_install debugging_install: +cgroup_install firewire_install gpio_install hv_install iio_install rpmb_install perf_install bootconfig_install spi_install usb_install virtio_install vm_install bpf_install objtool_install wmi_install pci_install debugging_install: $(call descend,$(@:_install=),install) liblockdep_install: @@ -134,7 +135,7 @@ kvm_stat_install: install: acpi_install cgroup_install cpupower_install gpio_install \ hv_install firewire_install iio_install liblockdep_install \ - perf_install selftests_install turbostat_install usb_install \ + perf_install rpmb_install selftests_install turbostat_install usb_install \ virtio_install vm_install bpf_install x86_energy_perf_policy_install \ tmon_install freefall_install objtool_install kvm_stat_install \ wmi_install pci_install debugging_install intel-speed-select_install @@ -164,6 +165,9 @@ perf_clean: $(Q)mkdir -p $(PERF_O) . $(Q)$(MAKE) --no-print-directory -C perf O=$(PERF_O) subdir= clean +rpmb_clean: + $(call descend,$(@:_clean=),clean) + selftests_clean: $(call descend,testing/$(@:_clean=),clean) @@ -180,7 +184,7 @@ build_clean: $(call descend,build,clean) clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean \ - perf_clean selftests_clean turbostat_clean bootconfig_clean spi_clean usb_clean virtio_clean \ + perf_clean rpmb_clean selftests_clean turbostat_clean bootconfig_clean spi_clean usb_clean virtio_clean \ vm_clean bpf_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \ gpio_clean objtool_clean leds_clean wmi_clean pci_clean firmware_clean debugging_clean \ diff --git a/tools/rpmb/.gitignore b/tools/rpmb/.gitignore new file mode 100644 index ..218f680548e6 --- /dev/null +++ b/tools/rpmb/.gitignore @@ -0,0 +1,2 @@ +*.o +rpmb diff --git a/tools/rpmb/Makefile b/tools/rpmb/Makefile new file mode 100644 index 0
RPMB user space ABI
Hi, Last year while I was implementing a virtio-rpmb backend for QEMU I ended up using patches from the ACRN tree which was based on Thomas' patches last posted in 2016: https://lore.kernel.org/lkml/1478548394-8184-1-git-send-email-tomas.wink...@intel.com/ which I bastardised into a testing tree on a more recent kernel: https://git.linaro.org/people/alex.bennee/linux.git/log/?h=testing/virtio-rpmb The main reason I hacked them around was because the VirtIO spec had since been finalised and had a very different framing structure. The original proposed ABI provided for an ioctl which sent JDEC frames to the underlying device. This was later expanded to support NVME style frames. Neither of these frame sequences matched the final VirtIO specification. It seems to me having the ioctl ABI at this level exposes too many underlying HW details to user space. With the number of HW devices that providing RPMB features likely to grow from the current 3 (eMMC/JDEC, NVME, VirtIO) it seems this ABI should operate at a higher level, e.g.: PROGRAM_KEY GET_WRITE_COUNTER WRITE_DATA READ_DATA and I guess some sort of asynchronous result check? It would then be for the kernel to take the higher level concepts and translate them to the final frames required to talk to the actual HW (if indeed there is some). Does this seem reasonable? Is this orthogonal to any access to RPMB partitions that file-systems might want to do? -- Alex Bennée
Re: [PATCH v1 3/3] kernel/configs: don't include PCI_QUIRKS in KVM guest configs
Marc Zyngier writes: > On 2020-08-04 15:44, Alex Bennée wrote: >> Marc Zyngier writes: >> >>> On 2020-08-04 13:44, Alex Bennée wrote: >>>> The VIRTIO_PCI support is an idealised PCI bus, we don't need a bunch >>>> of bloat for real world hardware for a VirtIO guest. >>> >>> Who says this guest will only have virtio devices? >> >> This is true - although what is the point of kvm_guest.config? We >> certainly turn on a whole bunch of virt optimised pathways with >> PARAVIRT >> and HYPERVISOR_GUEST along with the rest of VirtIO. > > Most of which actually qualifies as bloat itself as far as KVM/arm64 > is concerned... So here is the question - does the kernel care about having a blessed config for a minimal viable guest? They are certainly used in the cloud but I understand the kernel is trying to get away from having a zoo of configs. What is the actual point of kvm_guest.config? Just an easy enabling for developers? > > M. -- Alex Bennée
Re: [RFC PATCH v1 0/3] put arm64 kvm_config on a diet
Ard Biesheuvel writes: > On Tue, 4 Aug 2020 at 14:45, Alex Bennée wrote: >> >> Hi, >> >> When building guest kernels for virtualisation we were bringing in a >> bunch of stuff from physical hardware which we don't need for our >> idealised fixable virtual PCI devices. This series makes some Kconfig >> changes to allow the ThunderX and XGene PCI drivers to be compiled >> out. It also drops PCI_QUIRKS from the KVM guest build as a virtual >> PCI device should be quirk free. >> > > What about PCI passthrough? That is a good point - how much of the host PCI controller is visible to a pass-through guest? AIUI in passthrough the driver only interacts with the particular cards IO window. How many quirks are visible just at the device level (rather than the bus itself)? That said I think the last patch might get dropped as long as the user has the option to slim down their kernel with the first two. > >> This is my first time hacking around Kconfig so I hope I've got the >> balance between depends and selects right but please let be know if it >> could be specified in a cleaner way. >> >> Alex Bennée (3): >> arm64: allow de-selection of ThunderX PCI controllers >> arm64: gate the whole of pci-xgene on CONFIG_PCI_XGENE >> kernel/configs: don't include PCI_QUIRKS in KVM guest configs >> >> arch/arm64/Kconfig.platforms| 2 ++ >> arch/arm64/configs/defconfig| 1 + >> drivers/pci/controller/Kconfig | 7 +++ >> drivers/pci/controller/Makefile | 8 +++- >> kernel/configs/kvm_guest.config | 1 + >> 5 files changed, 14 insertions(+), 5 deletions(-) >> >> -- >> 2.20.1 >> >> >> ___ >> linux-arm-kernel mailing list >> linux-arm-ker...@lists.infradead.org >> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel -- Alex Bennée
Re: [PATCH v1 3/3] kernel/configs: don't include PCI_QUIRKS in KVM guest configs
Marc Zyngier writes: > On 2020-08-04 13:44, Alex Bennée wrote: >> The VIRTIO_PCI support is an idealised PCI bus, we don't need a bunch >> of bloat for real world hardware for a VirtIO guest. > > Who says this guest will only have virtio devices? This is true - although what is the point of kvm_guest.config? We certainly turn on a whole bunch of virt optimised pathways with PARAVIRT and HYPERVISOR_GUEST along with the rest of VirtIO. > Or even, virtio devices without bugs? Given that said device can > come from any VMM, I'm not sure this is the right thing to do. Perhaps this patch is one too far. I don't mind dropping it as long as I can still slim down the kernels I know don't need the extra bloat. > > Thanks, > > M. > >> >> Signed-off-by: Alex Bennée >> --- >> kernel/configs/kvm_guest.config | 1 + >> 1 file changed, 1 insertion(+) >> >> diff --git a/kernel/configs/kvm_guest.config >> b/kernel/configs/kvm_guest.config >> index 208481d91090..672863a2fdf1 100644 >> --- a/kernel/configs/kvm_guest.config >> +++ b/kernel/configs/kvm_guest.config >> @@ -13,6 +13,7 @@ CONFIG_IP_PNP_DHCP=y >> CONFIG_BINFMT_ELF=y >> CONFIG_PCI=y >> CONFIG_PCI_MSI=y >> +CONFIG_PCI_QUIRKS=n >> CONFIG_DEBUG_KERNEL=y >> CONFIG_VIRTUALIZATION=y >> CONFIG_HYPERVISOR_GUEST=y -- Alex Bennée
[RFC PATCH v1 0/3] put arm64 kvm_config on a diet
Hi, When building guest kernels for virtualisation we were bringing in a bunch of stuff from physical hardware which we don't need for our idealised fixable virtual PCI devices. This series makes some Kconfig changes to allow the ThunderX and XGene PCI drivers to be compiled out. It also drops PCI_QUIRKS from the KVM guest build as a virtual PCI device should be quirk free. This is my first time hacking around Kconfig so I hope I've got the balance between depends and selects right but please let be know if it could be specified in a cleaner way. Alex Bennée (3): arm64: allow de-selection of ThunderX PCI controllers arm64: gate the whole of pci-xgene on CONFIG_PCI_XGENE kernel/configs: don't include PCI_QUIRKS in KVM guest configs arch/arm64/Kconfig.platforms| 2 ++ arch/arm64/configs/defconfig| 1 + drivers/pci/controller/Kconfig | 7 +++ drivers/pci/controller/Makefile | 8 +++- kernel/configs/kvm_guest.config | 1 + 5 files changed, 14 insertions(+), 5 deletions(-) -- 2.20.1
[PATCH v1 1/3] arm64: allow de-selection of ThunderX PCI controllers
For a pure VirtIO guest bringing in all the PCI quirk handling adds a significant amount of bloat to kernel we don't need. Solve this by adding a CONFIG symbol for the ThunderX PCI devices and allowing it to be turned off. Saving over 300k from the uncompressed vmlinux: -rwxr-xr-x 1 alex alex 85652472 Aug 3 16:48 vmlinux* -rwxr-xr-x 1 alex alex 86033880 Aug 3 16:39 vmlinux.orig* Signed-off-by: Alex Bennée Cc: Robert Richter Cc: linux-...@vger.kernel.org Cc: linux-arm-ker...@lists.infradead.org --- arch/arm64/Kconfig.platforms| 2 ++ arch/arm64/configs/defconfig| 1 + drivers/pci/controller/Kconfig | 7 +++ drivers/pci/controller/Makefile | 4 ++-- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 8dd05b2a925c..a328eebdaa59 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -253,12 +253,14 @@ config ARCH_SPRD config ARCH_THUNDER bool "Cavium Inc. Thunder SoC Family" +select PCI_THUNDER help This enables support for Cavium's Thunder Family of SoCs. config ARCH_THUNDER2 bool "Cavium ThunderX2 Server Processors" select GPIOLIB +select PCI_THUNDER help This enables support for Cavium's ThunderX2 CN99XX family of server processors. diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 2ca7ba69c318..d840cba99941 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -199,6 +199,7 @@ CONFIG_PCI_HOST_GENERIC=y CONFIG_PCI_XGENE=y CONFIG_PCIE_ALTERA=y CONFIG_PCIE_ALTERA_MSI=y +CONFIG_PCI_THUNDER=y CONFIG_PCI_HOST_THUNDER_PEM=y CONFIG_PCI_HOST_THUNDER_ECAM=y CONFIG_PCIE_ROCKCHIP_HOST=m diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index adddf21fa381..28335ffa5d48 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -286,6 +286,13 @@ config PCI_LOONGSON Say Y here if you want to enable PCI controller support on Loongson systems. +config PCI_THUNDER + bool "Thunder X PCIE controllers" + depends on ARM64 + select PCI_QUIRKS + help + Say Y here to enable ThunderX ECAM and PEM PCI controllers. + source "drivers/pci/controller/dwc/Kconfig" source "drivers/pci/controller/mobiveil/Kconfig" source "drivers/pci/controller/cadence/Kconfig" diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile index efd9733ead26..8fad4781a5d3 100644 --- a/drivers/pci/controller/Makefile +++ b/drivers/pci/controller/Makefile @@ -45,8 +45,8 @@ obj-y += mobiveil/ # ARM64 and use internal ifdefs to only build the pieces we need # depending on whether ACPI, the DT driver, or both are enabled. +obj-$(CONFIG_PCI_THUNDER) += pci-thunder-ecam.o +obj-$(CONFIG_PCI_THUNDER) += pci-thunder-pem.o ifdef CONFIG_PCI -obj-$(CONFIG_ARM64) += pci-thunder-ecam.o -obj-$(CONFIG_ARM64) += pci-thunder-pem.o obj-$(CONFIG_ARM64) += pci-xgene.o endif -- 2.20.1
[PATCH v1 2/3] arm64: gate the whole of pci-xgene on CONFIG_PCI_XGENE
This is a little weirder as bits of the file are already conditioned on the exiting symbol. Either way they are not actually needed for non-xgene machines saving another 12k: -rwxr-xr-x 1 alex alex 86033880 Aug 3 16:39 vmlinux.orig* -rwxr-xr-x 1 alex alex 85652472 Aug 3 16:54 vmlinux.rm-thunder* -rwxr-xr-x 1 alex alex 85639808 Aug 3 17:12 vmlinux* Signed-off-by: Alex Bennée --- drivers/pci/controller/Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile index 8fad4781a5d3..3b9b72f5773a 100644 --- a/drivers/pci/controller/Makefile +++ b/drivers/pci/controller/Makefile @@ -47,6 +47,4 @@ obj-y += mobiveil/ obj-$(CONFIG_PCI_THUNDER) += pci-thunder-ecam.o obj-$(CONFIG_PCI_THUNDER) += pci-thunder-pem.o -ifdef CONFIG_PCI -obj-$(CONFIG_ARM64) += pci-xgene.o -endif +obj-$(CONFIG_PCI_XGENE) += pci-xgene.o -- 2.20.1
[PATCH v1 3/3] kernel/configs: don't include PCI_QUIRKS in KVM guest configs
The VIRTIO_PCI support is an idealised PCI bus, we don't need a bunch of bloat for real world hardware for a VirtIO guest. Signed-off-by: Alex Bennée --- kernel/configs/kvm_guest.config | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/configs/kvm_guest.config b/kernel/configs/kvm_guest.config index 208481d91090..672863a2fdf1 100644 --- a/kernel/configs/kvm_guest.config +++ b/kernel/configs/kvm_guest.config @@ -13,6 +13,7 @@ CONFIG_IP_PNP_DHCP=y CONFIG_BINFMT_ELF=y CONFIG_PCI=y CONFIG_PCI_MSI=y +CONFIG_PCI_QUIRKS=n CONFIG_DEBUG_KERNEL=y CONFIG_VIRTUALIZATION=y CONFIG_HYPERVISOR_GUEST=y -- 2.20.1
Re: [PATCH v2 0/5] virtio mmio specification enhancement
Alex Bennée writes: > Pincus, Josh writes: > >> Hi, >> >> >> >> We were looking into a similar enhancement for the Virt I/O MMIO transport >> and came across this project. >> >> This enhancement would be perfect for us. > > So there is certainly an interest in optimising MMIO based virtio and > the current read/ack cycle adds additional round trip time for any trap > and emulate hypervisor. However I think there is some resistance to > making MMIO a re-implementation of what PCI already gives us for "free". > > - Quantifying the memory foot-print difference between PCI/MMIO > > PCI gives a lot for free including a discovery and IRQ model already > designed to handle MSI/MSI-X. There is a claim that this brings in a > lot of bloat but I think there was some debate around the numbers. > My rough initial experiment with a PCI and non-PCI build with > otherwise identical VIRTIO configs results in the following: > > 16:40:15 c.282% [alex@zen:~/l/l/builds] review/rpmb|… + ls -l > arm64/vmlinux arm64.nopci/vmlinux > -rwxr-xr-x 1 alex alex 83914728 Jul 31 16:39 arm64.nopci/vmlinux* > -rwxr-xr-x 1 alex alex 86368080 Jul 31 16:33 arm64/vmlinux* > > which certainly implies there could be a fair amount of headroom for > an MMIO version to implement some features. However I don't know if > it's fully apples to apples as there maybe unneeded PCI bloat that a > virtio-only kernel doesn't need. Just following up after cutting the Xgene and ThunderX PCI bloat from the kernel the margin is a little smaller: -rwxr-xr-x 1 alex alex 83914728 Jul 31 16:39 arm64.nopci/vmlinux* -rwxr-xr-x 1 alex alex 85639808 Aug 3 17:12 arm64/vmlinux* -- Alex Bennée
Re: [PATCH v2 0/5] virtio mmio specification enhancement
Pincus, Josh writes: > Hi, > > > > We were looking into a similar enhancement for the Virt I/O MMIO transport > and came across this project. > > This enhancement would be perfect for us. So there is certainly an interest in optimising MMIO based virtio and the current read/ack cycle adds additional round trip time for any trap and emulate hypervisor. However I think there is some resistance to making MMIO a re-implementation of what PCI already gives us for "free". I believe the current questions that need to be addressed are: - Clear definitions in the spec on doorbells/notifications The current virtio spec uses different terms in some places so it would be nice to clarify the language and formalise what the standard expects from transports w.r.t the capabilities of notifications and doorbells. - Quantifying the memory foot-print difference between PCI/MMIO PCI gives a lot for free including a discovery and IRQ model already designed to handle MSI/MSI-X. There is a claim that this brings in a lot of bloat but I think there was some debate around the numbers. My rough initial experiment with a PCI and non-PCI build with otherwise identical VIRTIO configs results in the following: 16:40:15 c.282% [alex@zen:~/l/l/builds] review/rpmb|… + ls -l arm64/vmlinux arm64.nopci/vmlinux -rwxr-xr-x 1 alex alex 83914728 Jul 31 16:39 arm64.nopci/vmlinux* -rwxr-xr-x 1 alex alex 86368080 Jul 31 16:33 arm64/vmlinux* which certainly implies there could be a fair amount of headroom for an MMIO version to implement some features. However I don't know if it's fully apples to apples as there maybe unneeded PCI bloat that a virtio-only kernel doesn't need. What are the features you are most interested in? > Has there been any progress since Feb, 2020? It looks like the effort > might have stalled? I can't speak to the OP's but there is certainly interest from others that are not the original posters. -- Alex Bennée
Re: [PATCH v2 04/12] arm64: docs: cpu-feature-registers: Document ID_AA64PFR1_EL1
Dave Martin writes: > Commit d71be2b6c0e1 ("arm64: cpufeature: Detect SSBS and advertise > to userspace") exposes ID_AA64PFR1_EL1 to userspace, but didn't > update the documentation to match. > > Add it. > > Signed-off-by: Dave Martin > > --- > > Note to maintainers: > > * This patch has been racing with various other attempts to fix >the same documentation in the meantime. > >Since this patch only fixes the documenting for pre-existing >features, it can safely be dropped if appropriate. > >The _new_ documentation relating to BTI feature reporting >is in a subsequent patch, and needs to be retained. > --- > Documentation/arm64/cpu-feature-registers.rst | 15 +++ > 1 file changed, 11 insertions(+), 4 deletions(-) > > diff --git a/Documentation/arm64/cpu-feature-registers.rst > b/Documentation/arm64/cpu-feature-registers.rst > index 2955287..b86828f 100644 > --- a/Documentation/arm64/cpu-feature-registers.rst > +++ b/Documentation/arm64/cpu-feature-registers.rst > @@ -168,8 +168,15 @@ infrastructure: > +--+-+-+ > > > - 3) MIDR_EL1 - Main ID Register > + 3) ID_AA64PFR1_EL1 - Processor Feature Register 1 > + +--+-+-+ > + | Name | bits | visible | > + +--+-+-+ > + | SSBS | [7-4] |y| > + +--+-+-+ > + > > + 4) MIDR_EL1 - Main ID Register > +--+-+-+ > | Name | bits | visible | > +--+-+-+ > @@ -188,7 +195,7 @@ infrastructure: > as available on the CPU where it is fetched and is not a system > wide safe value. > > - 4) ID_AA64ISAR1_EL1 - Instruction set attribute register 1 > + 5) ID_AA64ISAR1_EL1 - Instruction set attribute register 1 If I'm not mistaken .rst has support for auto-enumeration if the # character is used. That might reduce the pain of re-numbering in future. > > +--+-+-+ > | Name | bits | visible | > @@ -210,7 +217,7 @@ infrastructure: > | DPB | [3-0] |y| > +--+-+-+ > > - 5) ID_AA64MMFR2_EL1 - Memory model feature register 2 > + 6) ID_AA64MMFR2_EL1 - Memory model feature register 2 > > +--+-+-+ > | Name | bits | visible | > @@ -218,7 +225,7 @@ infrastructure: > | AT | [35-32] |y| > +--+-+-+ > > - 6) ID_AA64ZFR0_EL1 - SVE feature ID register 0 > + 7) ID_AA64ZFR0_EL1 - SVE feature ID register 0 > > +--+-+-+ > | Name | bits | visible | -- Alex Bennée
Re: [PATCH] arm64/sve: fix genksyms generation
Arnd Bergmann writes: > On Mon, Jun 17, 2019 at 1:26 PM Will Deacon wrote: >> >> Hi Arnd, >> >> On Mon, Jun 17, 2019 at 12:42:11PM +0200, Arnd Bergmann wrote: >> > genksyms does not understand __uint128_t, so we get a build failure >> > in the fpsimd module when it cannot export a symbol right: >> >> The fpsimd code is builtin, so which module is actually failing? My >> allmodconfig build succeeds, so I must be missing something. > > It happened for me on randconfig builds, you can find one such configuration > at https://pastebin.com/cU8iQ4ta now. I was building this with clang > rather than gcc, which may affect the issue, but I assumed not. > >> > WARNING: EXPORT symbol "kernel_neon_begin" [vmlinux] version generation >> > failed, symbol will not be versioned. >> > /home/arnd/cross/x86_64/gcc-8.1.0-nolibc/aarch64-linux/bin/aarch64-linux-ld: >> > arch/arm64/kernel/fpsimd.o: relocation R_AARCH64_ABS32 against >> > `__crc_kernel_neon_begin' can not be used when making a shared object >> > arch/arm64/kernel/fpsimd.o:(.data+0x0): dangerous relocation: unsupported >> > relocation >> > arch/arm64/kernel/fpsimd.o:(".discard.addressable"+0x0): dangerous >> > relocation: unsupported relocation >> > arch/arm64/kernel/fpsimd.o:(".discard.addressable"+0x8): dangerous >> > relocation: unsupported relocation >> > >> > We could teach genksyms about the type, but it's easier to just >> > work around it by defining that type locally in a way that genksyms >> > understands. >> > >> > Fixes: 41040cf7c5f0 ("arm64/sve: Fix missing SVE/FPSIMD endianness >> > conversions") >> >> I can't see which part of that patch causes the problem, so I'm a bit wary >> of the fix. We've been using __uint128_t for a while now, and I see there's >> one in the x86 kvm code as well, so it would be nice to understand what's >> happening here so that we can avoid running into it in future as well. > > The problem is only in files that export a symbol. This is also the > case in arch/x86/kernel/kvm.c, but it may be lucky because the > type only appears /after/ the last export in that file. > >> > Signed-off-by: Arnd Bergmann >> > --- >> > arch/arm64/kernel/fpsimd.c | 3 +++ >> > 1 file changed, 3 insertions(+) >> > >> > diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c >> > index 07f238ef47ae..2aba07cccf50 100644 >> > --- a/arch/arm64/kernel/fpsimd.c >> > +++ b/arch/arm64/kernel/fpsimd.c >> > @@ -400,6 +400,9 @@ static int __init sve_sysctl_init(void) { return 0; } >> > #define ZREG(sve_state, vq, n) ((char *)(sve_state) +\ >> > (SVE_SIG_ZREG_OFFSET(vq, n) - SVE_SIG_REGS_OFFSET)) >> > >> > +#ifdef __GENKSYMS__ >> > +typedef __u64 __uint128_t[2]; >> > +#endif >> >> I suspect I need to figure out what genksyms is doing, but I'm nervous >> about exposing this as an array type without understanding whether or >> not that has consequences for its operation. > > The entire point is genksyms is to ensure that types of exported symbols > are compatible. To do this, it has a limited parser for C source code that > understands the basic types (char, int, long, _Bool, etc) and how to > aggregate them into structs and function arguments. This process has > always been fragile, and it clearly breaks when it fails to understand a > particular type. Shouldn't the solution for this be to fix genksyms to be less fragile and more understanding? The code base doesn't seem to be full of these sorts of ifdef workarounds. > > Arnd -- Alex Bennée
[PATCH v1 1/2] kvm: arm64: handle single-step during SError exceptions
When an SError arrives during single-step it may be delivered before the step completes. In that case the DBG_SPSR_SS bit will have flipped as the instruction executed. After handling the abort in handle_exit() we test to see if the bit is clear and we were single-stepping before deciding if we need to exit to user space. Signed-off-by: Alex Bennée --- arch/arm64/kvm/handle_exit.c | 8 +++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 3e645ec9e751..3ba8c4a3bcff 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -28,6 +28,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include "trace.h" @@ -250,7 +251,12 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, return 1; case ARM_EXCEPTION_EL1_SERROR: kvm_inject_vabt(vcpu); - return 1; + /* We may still need to return for single-step */ + if (!(*vcpu_cpsr(vcpu) & DBG_SPSR_SS) + && kvm_arm_handle_step_debug(vcpu, run)) + return 0; + else + return 1; case ARM_EXCEPTION_TRAP: return handle_trap_exceptions(vcpu, run); case ARM_EXCEPTION_HYP_GONE: -- 2.15.0
[PATCH v1 2/2] kvm: arm64: handle single-step of hyp emulated mmio instructions
There is a fast-path of MMIO emulation inside hyp mode. The handling of single-step is broadly the same as kvm_arm_handle_step_debug() except we just setup ESR/HSR so handle_exit() does the correct thing as we exit. For the case of an emulated illegal access causing an SError we will exit via the ARM_EXCEPTION_EL1_SERROR path in handle_exit(). We behave as we would during a real SError and clear the DBG_SPSR_SS bit for the emulated instruction. Signed-off-by: Alex Bennée --- arch/arm64/kvm/hyp/switch.c | 37 ++--- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c index 525c01f48867..f7c651f3a8c0 100644 --- a/arch/arm64/kvm/hyp/switch.c +++ b/arch/arm64/kvm/hyp/switch.c @@ -22,6 +22,7 @@ #include #include #include +#include static bool __hyp_text __fpsimd_enabled_nvhe(void) { @@ -269,7 +270,11 @@ static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu) return true; } -static void __hyp_text __skip_instr(struct kvm_vcpu *vcpu) +/* Skip an instruction which has been emulated. Returns true if + * execution can continue or false if we need to exit hyp mode because + * single-step was in effect. + */ +static bool __hyp_text __skip_instr(struct kvm_vcpu *vcpu) { *vcpu_pc(vcpu) = read_sysreg_el2(elr); @@ -282,6 +287,14 @@ static void __hyp_text __skip_instr(struct kvm_vcpu *vcpu) } write_sysreg_el2(*vcpu_pc(vcpu), elr); + + if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) { + vcpu->arch.fault.esr_el2 = + (ESR_ELx_EC_SOFTSTP_LOW << ESR_ELx_EC_SHIFT) | 0x22; + return false; + } else { + return true; + } } int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu) @@ -342,13 +355,21 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu) int ret = __vgic_v2_perform_cpuif_access(vcpu); if (ret == 1) { - __skip_instr(vcpu); - goto again; + if (__skip_instr(vcpu)) + goto again; + else + exit_code = ARM_EXCEPTION_TRAP; } if (ret == -1) { - /* Promote an illegal access to an SError */ - __skip_instr(vcpu); + /* Promote an illegal access to an +* SError. If we would be returning +* due to single-step clear the SS +* bit so handle_exit knows what to +* do after dealing with the error. +*/ + if (!__skip_instr(vcpu)) + *vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS; exit_code = ARM_EXCEPTION_EL1_SERROR; } @@ -363,8 +384,10 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu) int ret = __vgic_v3_perform_cpuif_access(vcpu); if (ret == 1) { - __skip_instr(vcpu); - goto again; + if (__skip_instr(vcpu)) + goto again; + else + exit_code = ARM_EXCEPTION_TRAP; } /* 0 falls through to be handled out of EL2 */ -- 2.15.0
[RFC PATCH] kvm: arm64: handle single-step of hyp emulated mmio instructions
There is a fast-path of MMIO emulation inside hyp mode. The handling of single-step is broadly the same as kvm_arm_handle_step_debug() except we just setup ESR/HSR so handle_exit() does the correct thing as we exit. For the case of an emulated illegal access causing an SError we signal to handle_exit() by clearing the DBG_SPSR_SS bit as would have actually happened had the hardware really single-stepped the instruction. [AJB: currently compile tested only] Signed-off-by: Alex Bennée --- arch/arm64/kvm/handle_exit.c | 8 +++- arch/arm64/kvm/hyp/switch.c | 37 ++--- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index af1c804742f6..128120f04e0e 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -28,6 +28,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include "trace.h" @@ -242,7 +243,12 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, return 1; case ARM_EXCEPTION_EL1_SERROR: kvm_inject_vabt(vcpu); - return 1; + /* We may still need to return for single-step */ + if (!(*vcpu_cpsr(vcpu) & DBG_SPSR_SS) + && kvm_arm_handle_step_debug(vcpu, run)) + return 0; + else + return 1; case ARM_EXCEPTION_TRAP: return handle_trap_exceptions(vcpu, run); case ARM_EXCEPTION_HYP_GONE: diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c index 945e79c641c4..a6712f179b52 100644 --- a/arch/arm64/kvm/hyp/switch.c +++ b/arch/arm64/kvm/hyp/switch.c @@ -22,6 +22,7 @@ #include #include #include +#include static bool __hyp_text __fpsimd_enabled_nvhe(void) { @@ -263,7 +264,11 @@ static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu) return true; } -static void __hyp_text __skip_instr(struct kvm_vcpu *vcpu) +/* Skip an instruction which has been emulated. Returns true if + * execution can continue or false if we need to exit hyp mode because + * single-step was in effect. + */ +static bool __hyp_text __skip_instr(struct kvm_vcpu *vcpu) { *vcpu_pc(vcpu) = read_sysreg_el2(elr); @@ -276,6 +281,14 @@ static void __hyp_text __skip_instr(struct kvm_vcpu *vcpu) } write_sysreg_el2(*vcpu_pc(vcpu), elr); + + if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) { + vcpu->arch.fault.esr_el2 = + (ESR_ELx_EC_SOFTSTP_LOW << ESR_ELx_EC_SHIFT) | 0x22; + return false; + } else { + return true; + } } int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu) @@ -336,13 +349,21 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu) int ret = __vgic_v2_perform_cpuif_access(vcpu); if (ret == 1) { - __skip_instr(vcpu); - goto again; + if (__skip_instr(vcpu)) + goto again; + else + exit_code = ARM_EXCEPTION_TRAP; } if (ret == -1) { - /* Promote an illegal access to an SError */ - __skip_instr(vcpu); + /* Promote an illegal access to an +* SError. If we would be returning +* due to single-step clear the SS +* bit so handle_exit knows what to +* do after dealing with the error. +*/ + if (!__skip_instr(vcpu)) + *vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS; exit_code = ARM_EXCEPTION_EL1_SERROR; } @@ -357,8 +378,10 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu) int ret = __vgic_v3_perform_cpuif_access(vcpu); if (ret == 1) { - __skip_instr(vcpu); - goto again; + if (__skip_instr(vcpu)) + goto again; + else + exit_code = ARM_EXCEPTION_TRAP; } /* 0 falls through to be handled out of EL2 */ -- 2.15.0
[PATCH v3 2/3] kvm: arm64: handle single-stepping trapped instructions
If we are using guest debug to single-step the guest we need to ensure we exit after emulating the instruction. This only affects instructions completely emulated by the kernel. For userspace emulated instructions we need to exit and return to complete the emulation. The kvm_arm_handle_step_debug() helper sets up the necessary exit state if needed. Signed-off-by: Alex Bennée Reviewed-by: Julien Thierry --- v2 - use helper from patch 1 - if (handled > 0) instead of if (handled) so errors propagate --- arch/arm64/kvm/handle_exit.c | 47 +++- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 7debb74843a0..af1c804742f6 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -178,6 +178,38 @@ static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu) return arm_exit_handlers[hsr_ec]; } +/* + * We may be single-stepping an emulated instruction. If the emulation + * has been completed in-kernel we can return to userspace with a + * KVM_EXIT_DEBUG, otherwise the userspace needs to complete its + * emulation first. + */ + +static int handle_trap_exceptions(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + int handled; + + /* +* See ARM ARM B1.14.1: "Hyp traps on instructions +* that fail their condition code check" +*/ + if (!kvm_condition_valid(vcpu)) { + kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); + handled = 1; + } else { + exit_handle_fn exit_handler; + + exit_handler = kvm_get_exit_handler(vcpu); + handled = exit_handler(vcpu, run); + } + + /* helper sets exit_reason if we need to return to userspace */ + if (handled > 0 && kvm_arm_handle_step_debug(vcpu, run)) + handled = 0; + + return handled; +} + /* * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on * proper exit to userspace. @@ -185,8 +217,6 @@ static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu) int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, int exception_index) { - exit_handle_fn exit_handler; - if (ARM_SERROR_PENDING(exception_index)) { u8 hsr_ec = ESR_ELx_EC(kvm_vcpu_get_hsr(vcpu)); @@ -214,18 +244,7 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, kvm_inject_vabt(vcpu); return 1; case ARM_EXCEPTION_TRAP: - /* -* See ARM ARM B1.14.1: "Hyp traps on instructions -* that fail their condition code check" -*/ - if (!kvm_condition_valid(vcpu)) { - kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); - return 1; - } - - exit_handler = kvm_get_exit_handler(vcpu); - - return exit_handler(vcpu, run); + return handle_trap_exceptions(vcpu, run); case ARM_EXCEPTION_HYP_GONE: /* * EL2 has been reset to the hyp-stub. This happens when a guest -- 2.15.0
[PATCH v3 1/3] kvm: arm debug: introduce helper for single-step
After emulating instructions we may want return to user-space to handle a single-step. If single-step is enabled the helper set the run structure for return and returns true. Signed-off-by: Alex Bennée Reviewed-by: Julien Thierry --- v2 - kvm_arm_maybe_return_debug -> kvm_arm_handle_step_debug - return bool, true if return to userspace is required --- arch/arm/include/asm/kvm_host.h | 5 + arch/arm64/include/asm/kvm_host.h | 1 + arch/arm64/kvm/debug.c| 22 ++ 3 files changed, 28 insertions(+) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 4a879f6ff13b..26a1ea6c6542 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -285,6 +285,11 @@ static inline void kvm_arm_init_debug(void) {} static inline void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) {} static inline void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) {} static inline void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu) {} +static inline bool kvm_arm_handle_step_debug(struct kvm_vcpu *vcpu, +struct kvm_run *run) +{ + return false; +} int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr); diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index e923b58606e2..bbfd6a2adb2b 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -369,6 +369,7 @@ void kvm_arm_init_debug(void); void kvm_arm_setup_debug(struct kvm_vcpu *vcpu); void kvm_arm_clear_debug(struct kvm_vcpu *vcpu); void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu); +bool kvm_arm_handle_step_debug(struct kvm_vcpu *vcpu, struct kvm_run *run); int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr); int kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu, diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index dbadfaf850a7..95afd22a4634 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -221,3 +221,25 @@ void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) } } } + + +/* + * When KVM has successfully emulated the instruction we might want to + * return to user space with a KVM_EXIT_DEBUG. We can only do this + * once the emulation is complete though so for userspace emulations + * we have to wait until we have re-entered KVM before calling this + * helper. + * + * Return true (and set exit_reason) to return to userspace or false + * if no further action required. + */ + +bool kvm_arm_handle_step_debug(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) { + run->exit_reason = KVM_EXIT_DEBUG; + run->debug.arch.hsr = ESR_ELx_EC_SOFTSTP_LOW << ESR_ELx_EC_SHIFT; + return true; + } + return false; +} -- 2.15.0
[PATCH v3 3/3] kvm: arm64: handle single-step of userspace mmio instructions
The system state of KVM when using userspace emulation is not complete until we return into KVM_RUN. To handle mmio related updates we wait until they have been committed and then schedule our KVM_EXIT_DEBUG. The kvm_arm_handle_step_debug() helper tells us if we need to return and sets up the exit_reason for us. Signed-off-by: Alex Bennée --- v2 - call helper directly from kvm_arch_vcpu_ioctl_run v3 - return 0 (ioctl success) instead of 1 --- virt/kvm/arm/arm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index 95cba0799828..b40440defca1 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c @@ -625,6 +625,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) ret = kvm_handle_mmio_return(vcpu, vcpu->run); if (ret) return ret; + if (kvm_arm_handle_step_debug(vcpu, vcpu->run)) + return 0; + } if (run->immediate_exit) -- 2.15.0
Re: [PATCH v2 3/3] kvm: arm64: handle single-step of userspace mmio instructions
Julien Thierry writes: > Hi Alex, > > On 09/11/17 17:00, Alex Bennée wrote: >> The system state of KVM when using userspace emulation is not complete >> until we return into KVM_RUN. To handle mmio related updates we wait >> until they have been committed and then schedule our KVM_EXIT_DEBUG. >> >> The kvm_arm_handle_step_debug() helper tells us if we need to return >> and sets up the exit_reason for us. >> >> Signed-off-by: Alex Bennée >> >> --- >> v2 >>- call helper directly from kvm_arch_vcpu_ioctl_run >> --- >> virt/kvm/arm/arm.c | 3 +++ >> 1 file changed, 3 insertions(+) >> >> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c >> index 95cba0799828..2991adfaca9d 100644 >> --- a/virt/kvm/arm/arm.c >> +++ b/virt/kvm/arm/arm.c >> @@ -625,6 +625,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, >> struct kvm_run *run) >> ret = kvm_handle_mmio_return(vcpu, vcpu->run); >> if (ret) >> return ret; >> +if (kvm_arm_handle_step_debug(vcpu, vcpu->run)) >> +return 1; >> + > > In the previous patch, kvm_arch_vcpu_ioctl_run return 0 when telling > userspace about a debug exception. Shouldn't this branch return 0 > instead of 1? Probably - although in practice it makes no difference. In QEMU for example the test is if (run_ret < 0) to handle errors. Otherwise success is assumed. > Returning on non-zero for kvm_handle_mmio_return is done because it > means there was an error. This is not the case for > kvm_arm_handle_step_debug. > > The description in the comment of kvm_arch_vcpu_ioctl_run is not very > clear whether non-zero result should be used for errors or if only the > negative values are treated as such, and positive values seems to be > generally used to keep the vcpu going. So, I thought it might make > sense to always return the same value upon debug exceptions. There is a subtle mis-match between what gets passed back to the ioctl and what terminates the while() loop later on. As far as the ioctl is concerned it's 0 success and - error. Once you get to the while loop you'll only ever exit once ret is no longer > 0. Anyway for consistency we should certainly return 0, I'll fix it on the next iteration. > > Cheers, -- Alex Bennée
[PATCH] fixup! kvm: arm debug: introduce helper for single-step
--- arch/arm/include/asm/kvm_host.h | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index a2e881d6108e..26a1ea6c6542 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -286,7 +286,10 @@ static inline void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) {} static inline void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) {} static inline void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu) {} static inline bool kvm_arm_handle_step_debug(struct kvm_vcpu *vcpu, -struct kvm_run *run) {} +struct kvm_run *run) +{ + return false; +} int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr); -- 2.14.2
[PATCH v2 1/3] kvm: arm debug: introduce helper for single-step
After emulating instructions we may want return to user-space to handle a single-step. If single-step is enabled the helper set the run structure for return and returns true. Signed-off-by: Alex Bennée --- v2 - kvm_arm_maybe_return_debug -> kvm_arm_handle_step_debug - return bool, true if return to userspace is required --- arch/arm/include/asm/kvm_host.h | 2 ++ arch/arm64/include/asm/kvm_host.h | 1 + arch/arm64/kvm/debug.c| 22 ++ 3 files changed, 25 insertions(+) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 4a879f6ff13b..a2e881d6108e 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -285,6 +285,8 @@ static inline void kvm_arm_init_debug(void) {} static inline void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) {} static inline void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) {} static inline void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu) {} +static inline bool kvm_arm_handle_step_debug(struct kvm_vcpu *vcpu, +struct kvm_run *run) {} int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr); diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index e923b58606e2..bbfd6a2adb2b 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -369,6 +369,7 @@ void kvm_arm_init_debug(void); void kvm_arm_setup_debug(struct kvm_vcpu *vcpu); void kvm_arm_clear_debug(struct kvm_vcpu *vcpu); void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu); +bool kvm_arm_handle_step_debug(struct kvm_vcpu *vcpu, struct kvm_run *run); int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr); int kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu, diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index dbadfaf850a7..95afd22a4634 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -221,3 +221,25 @@ void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) } } } + + +/* + * When KVM has successfully emulated the instruction we might want to + * return to user space with a KVM_EXIT_DEBUG. We can only do this + * once the emulation is complete though so for userspace emulations + * we have to wait until we have re-entered KVM before calling this + * helper. + * + * Return true (and set exit_reason) to return to userspace or false + * if no further action required. + */ + +bool kvm_arm_handle_step_debug(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) { + run->exit_reason = KVM_EXIT_DEBUG; + run->debug.arch.hsr = ESR_ELx_EC_SOFTSTP_LOW << ESR_ELx_EC_SHIFT; + return true; + } + return false; +} -- 2.14.2
[PATCH v2 3/3] kvm: arm64: handle single-step of userspace mmio instructions
The system state of KVM when using userspace emulation is not complete until we return into KVM_RUN. To handle mmio related updates we wait until they have been committed and then schedule our KVM_EXIT_DEBUG. The kvm_arm_handle_step_debug() helper tells us if we need to return and sets up the exit_reason for us. Signed-off-by: Alex Bennée --- v2 - call helper directly from kvm_arch_vcpu_ioctl_run --- virt/kvm/arm/arm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index 95cba0799828..2991adfaca9d 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c @@ -625,6 +625,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) ret = kvm_handle_mmio_return(vcpu, vcpu->run); if (ret) return ret; + if (kvm_arm_handle_step_debug(vcpu, vcpu->run)) + return 1; + } if (run->immediate_exit) -- 2.14.2
[PATCH v2 2/3] kvm: arm64: handle single-stepping trapped instructions
If we are using guest debug to single-step the guest we need to ensure we exit after emulating the instruction. This only affects instructions completely emulated by the kernel. For userspace emulated instructions we need to exit and return to complete the emulation. The kvm_arm_handle_step_debug() helper sets up the necessary exit state if needed. Signed-off-by: Alex Bennée --- v2 - use helper from patch 1 - if (handled > 0) instead of if (handled) so errors propagate --- arch/arm64/kvm/handle_exit.c | 47 +++- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 7debb74843a0..af1c804742f6 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -178,6 +178,38 @@ static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu) return arm_exit_handlers[hsr_ec]; } +/* + * We may be single-stepping an emulated instruction. If the emulation + * has been completed in-kernel we can return to userspace with a + * KVM_EXIT_DEBUG, otherwise the userspace needs to complete its + * emulation first. + */ + +static int handle_trap_exceptions(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + int handled; + + /* +* See ARM ARM B1.14.1: "Hyp traps on instructions +* that fail their condition code check" +*/ + if (!kvm_condition_valid(vcpu)) { + kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); + handled = 1; + } else { + exit_handle_fn exit_handler; + + exit_handler = kvm_get_exit_handler(vcpu); + handled = exit_handler(vcpu, run); + } + + /* helper sets exit_reason if we need to return to userspace */ + if (handled > 0 && kvm_arm_handle_step_debug(vcpu, run)) + handled = 0; + + return handled; +} + /* * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on * proper exit to userspace. @@ -185,8 +217,6 @@ static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu) int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, int exception_index) { - exit_handle_fn exit_handler; - if (ARM_SERROR_PENDING(exception_index)) { u8 hsr_ec = ESR_ELx_EC(kvm_vcpu_get_hsr(vcpu)); @@ -214,18 +244,7 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, kvm_inject_vabt(vcpu); return 1; case ARM_EXCEPTION_TRAP: - /* -* See ARM ARM B1.14.1: "Hyp traps on instructions -* that fail their condition code check" -*/ - if (!kvm_condition_valid(vcpu)) { - kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); - return 1; - } - - exit_handler = kvm_get_exit_handler(vcpu); - - return exit_handler(vcpu, run); + return handle_trap_exceptions(vcpu, run); case ARM_EXCEPTION_HYP_GONE: /* * EL2 has been reset to the hyp-stub. This happens when a guest -- 2.14.2
Re: [PATCH v1 2/2] kvm: arm64: handle single-step of userspace mmio instructions
Christoffer Dall writes: > On Fri, Oct 06, 2017 at 12:39:21PM +0100, Alex Bennée wrote: >> The system state of KVM when using userspace emulation is not complete >> until we return into KVM_RUN. To handle mmio related updates we wait >> until they have been committed and then schedule our KVM_EXIT_DEBUG. >> >> I've introduced a new function kvm_arm_maybe_return_debug() to wrap up >> the differences between arm/arm64 which is currently null for arm. >> >> Signed-off-by: Alex Bennée >> --- >> arch/arm/include/asm/kvm_host.h | 2 ++ >> arch/arm64/include/asm/kvm_host.h | 1 + >> arch/arm64/kvm/debug.c| 21 + >> arch/arm64/kvm/handle_exit.c | 9 +++-- >> virt/kvm/arm/arm.c| 2 +- >> virt/kvm/arm/mmio.c | 3 ++- >> 6 files changed, 30 insertions(+), 8 deletions(-) >> >> diff --git a/arch/arm/include/asm/kvm_host.h >> b/arch/arm/include/asm/kvm_host.h >> index 4a879f6ff13b..aec943f6d123 100644 >> --- a/arch/arm/include/asm/kvm_host.h >> +++ b/arch/arm/include/asm/kvm_host.h >> @@ -285,6 +285,8 @@ static inline void kvm_arm_init_debug(void) {} >> static inline void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) {} >> static inline void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) {} >> static inline void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu) {} >> +static inline int kvm_arm_maybe_return_debug(struct kvm_vcpu *vcpu, >> +struct kvm_run *run) {} >> >> int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu, >> struct kvm_device_attr *attr); >> diff --git a/arch/arm64/include/asm/kvm_host.h >> b/arch/arm64/include/asm/kvm_host.h >> index e923b58606e2..fa67d21662f6 100644 >> --- a/arch/arm64/include/asm/kvm_host.h >> +++ b/arch/arm64/include/asm/kvm_host.h >> @@ -369,6 +369,7 @@ void kvm_arm_init_debug(void); >> void kvm_arm_setup_debug(struct kvm_vcpu *vcpu); >> void kvm_arm_clear_debug(struct kvm_vcpu *vcpu); >> void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu); >> +int kvm_arm_maybe_return_debug(struct kvm_vcpu *vcpu, struct kvm_run *run); >> int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu, >> struct kvm_device_attr *attr); >> int kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu, >> diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c >> index dbadfaf850a7..a10a18c55c87 100644 >> --- a/arch/arm64/kvm/debug.c >> +++ b/arch/arm64/kvm/debug.c >> @@ -221,3 +221,24 @@ void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) >> } >> } >> } >> + >> + >> +/* >> + * When KVM has successfully emulated the instruction we might want to >> + * return we a KVM_EXIT_DEBUG. We can only do this once the emulation >> + * is complete though so for userspace emulations we have to wait >> + * until we have re-entered KVM. >> + * >> + * Return > 0 to return to guest, 0 (and set exit_reason) on proper >> + * exit to userspace. >> + */ >> + >> +int kvm_arm_maybe_return_debug(struct kvm_vcpu *vcpu, struct kvm_run *run) >> +{ >> +if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) { >> +run->exit_reason = KVM_EXIT_DEBUG; >> +run->debug.arch.hsr = ESR_ELx_EC_SOFTSTP_LOW << >> ESR_ELx_EC_SHIFT; >> +return 0; >> +} >> +return 1; >> +} >> diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c >> index c918d291cb58..7b04f59217bf 100644 >> --- a/arch/arm64/kvm/handle_exit.c >> +++ b/arch/arm64/kvm/handle_exit.c >> @@ -202,13 +202,10 @@ static int handle_trap_exceptions(struct kvm_vcpu >> *vcpu, struct kvm_run *run) >> handled = exit_handler(vcpu, run); >> } >> >> -if (handled && (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)) { >> -handled = 0; >> -run->exit_reason = KVM_EXIT_DEBUG; >> -run->debug.arch.hsr = ESR_ELx_EC_SOFTSTP_LOW << >> ESR_ELx_EC_SHIFT; >> -} >> +if (handled) >> +return kvm_arm_maybe_return_debug(vcpu, run); > > Again, this seems to override the return value of exit_handler, which > may be something negative. > > Just so I'm clear: There's no intended functionality change of this > particular hunk, it's just to share the logic in > kvm_arm_maybe_return_debug, right? Yes, modulo the annoying semantics in the two places of the vcpu run ioctl loo
Re: [PATCH v1 2/2] kvm: arm64: handle single-step of userspace mmio instructions
Christoffer Dall writes: > On Fri, Oct 06, 2017 at 02:45:35PM +0100, Alex Bennée wrote: >> >> Julien Thierry writes: >> >> > On 06/10/17 12:39, Alex Bennée wrote: >> >> The system state of KVM when using userspace emulation is not complete >> >> until we return into KVM_RUN. To handle mmio related updates we wait >> >> until they have been committed and then schedule our KVM_EXIT_DEBUG. >> >> >> >> I've introduced a new function kvm_arm_maybe_return_debug() to wrap up >> >> the differences between arm/arm64 which is currently null for arm. >> >> >> >> Signed-off-by: Alex Bennée >> >> --- >> >> arch/arm/include/asm/kvm_host.h | 2 ++ >> >> arch/arm64/include/asm/kvm_host.h | 1 + >> >> arch/arm64/kvm/debug.c| 21 + >> >> arch/arm64/kvm/handle_exit.c | 9 +++-- >> >> virt/kvm/arm/arm.c| 2 +- >> >> virt/kvm/arm/mmio.c | 3 ++- >> >> 6 files changed, 30 insertions(+), 8 deletions(-) >> >> >> >> diff --git a/arch/arm/include/asm/kvm_host.h >> >> b/arch/arm/include/asm/kvm_host.h >> >> index 4a879f6ff13b..aec943f6d123 100644 >> >> --- a/arch/arm/include/asm/kvm_host.h >> >> +++ b/arch/arm/include/asm/kvm_host.h >> >> @@ -285,6 +285,8 @@ static inline void kvm_arm_init_debug(void) {} >> >> static inline void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) {} >> >> static inline void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) {} >> >> static inline void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu) {} >> >> +static inline int kvm_arm_maybe_return_debug(struct kvm_vcpu *vcpu, >> >> + struct kvm_run *run) {} >> >> >> > >> > This function should return 1. >> >> So I did ponder making this a bool, returning true if we need to exit >> and testing in v/k/a/arm.c exit leg rather than in the mmio handler. >> >> At the moment it mirrors the existing exit logic which follows -1 err, 0 >> return, >0 handled. But as I mentioned in the cover letter this fell >> down a bit when dealing with the mmio case. >> >> > >> >> int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu, >> >> struct kvm_device_attr *attr); >> >> diff --git a/arch/arm64/include/asm/kvm_host.h >> >> b/arch/arm64/include/asm/kvm_host.h >> >> index e923b58606e2..fa67d21662f6 100644 >> >> --- a/arch/arm64/include/asm/kvm_host.h >> >> +++ b/arch/arm64/include/asm/kvm_host.h >> >> @@ -369,6 +369,7 @@ void kvm_arm_init_debug(void); >> >> void kvm_arm_setup_debug(struct kvm_vcpu *vcpu); >> >> void kvm_arm_clear_debug(struct kvm_vcpu *vcpu); >> >> void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu); >> >> +int kvm_arm_maybe_return_debug(struct kvm_vcpu *vcpu, struct kvm_run >> >> *run); >> > >> > I feel the name could be a little bit more explicit: >> > >> > kvm_arm_trap_need_step_debug, kvm_arm_trap_step_return_debug, >> > kvm_arm_trap_need_return_debug. >> >> I wanted to keep the debug suffix so that's fine although I'm not so >> sure trap is correct because on the tail end of mmio emulation are we >> still trapping? >> >> Maybe kvm_arm_step_emulated_debug? > > I think you should name it: > > kvm_arm_should_complete_emulated_instr_debug() - or something better - Naming is hard :-/ > and call it directly from kvm_arch_vcpu_ioctl_run, so that it becomes: > > ret = kvm_handle_mmio_return(vcpu, vcpu->run); > if (ret) > return ret; > ret = kvm_arm_should_complete_emulated_instr_debug(vcpu); > if (ret) > return ret; This runs into the problem of slightly different ret semantics for here and in handle_exit. Maybe just having a bool response and: if (kvm_arm_should_complete_emulated_instr_debug(vcpu)) return 0; And then in handle_exit: if (handled == 1 && kvm_arm_should_complete_emulated_instr_debug(vcpu)) return 0; else return handled; ? > >> >> > At least, I think it would be nice that the name reflect that this >> > check is meant for emulated instructions. >> > >> > Otherwise: >> > >> > Reviewed-by: Julien Thierry >> > >> > Thanks, >> >> > Thanks, > -Christoffer -- Alex Bennée
Re: [PATCH v1 1/2] KVM: arm64: handle single-stepping trapped instructions
Christoffer Dall writes: > On Fri, Oct 06, 2017 at 12:39:20PM +0100, Alex Bennée wrote: >> If we are using guest debug to single-step the guest we need to ensure >> we exit after emulating the instruction. This only affects >> instructions completely emulated by the kernel. For userspace emulated >> instructions we need to exit and return to complete the emulation. >> >> We fake debug.arch.hsr to contain ESR_ELx_EC_SOFTSTP_LOW so QEMU knows >> it was a single-step event (and without altering the userspace ABI). >> >> Signed-off-by: Alex Bennée >> --- >> arch/arm64/kvm/handle_exit.c | 48 >> +++- >> 1 file changed, 34 insertions(+), 14 deletions(-) >> >> diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c >> index 7debb74843a0..c918d291cb58 100644 >> --- a/arch/arm64/kvm/handle_exit.c >> +++ b/arch/arm64/kvm/handle_exit.c >> @@ -178,6 +178,39 @@ static exit_handle_fn kvm_get_exit_handler(struct >> kvm_vcpu *vcpu) >> return arm_exit_handlers[hsr_ec]; >> } >> >> +/* >> + * When handling traps we need to ensure exit the guest if we >> + * completely emulated the instruction while single-stepping. Stuff to >> + * be emulated in userspace needs to complete that first. >> + */ > > I really don't understand the first sentence here. We are already out > of the guest, so do you mean a return to userspace? > I think the second sentence could be more clear as well. Is 'stuff' not > actually 'MMIO emulation' or 'emulation' more broadly? Your right - it's sloppily worded how about: /* * We may be single-stepping an emulated instruction. If the emulation * has been completed in-kernel we can return to userspace with a * KVM_EXIT_DEBUG, otherwise the userspace needs to complete it's * emulation first. */ For x86 there is also IO emulation but in principle anything that might be passed off to userspace to be completed should be done first. > >> + >> +static int handle_trap_exceptions(struct kvm_vcpu *vcpu, struct kvm_run >> *run) >> +{ >> +int handled; >> + >> +/* >> + * See ARM ARM B1.14.1: "Hyp traps on instructions >> + * that fail their condition code check" >> + */ >> +if (!kvm_condition_valid(vcpu)) { >> +kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); >> +handled = 1; >> +} else { >> +exit_handle_fn exit_handler; >> + >> +exit_handler = kvm_get_exit_handler(vcpu); >> +handled = exit_handler(vcpu, run); >> +} >> + >> +if (handled && (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)) { > > Don't you want if (handled == 1) or if (handled > 0) ? > > If there was an error I think we want to just return that to userspace > and not override it and present single-stepping. Yes, I'll fix it. > >> +handled = 0; >> +run->exit_reason = KVM_EXIT_DEBUG; >> +run->debug.arch.hsr = ESR_ELx_EC_SOFTSTP_LOW << >> ESR_ELx_EC_SHIFT; >> +} >> + >> +return handled; >> +} >> + >> /* >> * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on >> * proper exit to userspace. >> @@ -185,8 +218,6 @@ static exit_handle_fn kvm_get_exit_handler(struct >> kvm_vcpu *vcpu) >> int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, >> int exception_index) >> { >> -exit_handle_fn exit_handler; >> - >> if (ARM_SERROR_PENDING(exception_index)) { >> u8 hsr_ec = ESR_ELx_EC(kvm_vcpu_get_hsr(vcpu)); >> >> @@ -214,18 +245,7 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run >> *run, >> kvm_inject_vabt(vcpu); >> return 1; >> case ARM_EXCEPTION_TRAP: >> -/* >> - * See ARM ARM B1.14.1: "Hyp traps on instructions >> - * that fail their condition code check" >> - */ >> -if (!kvm_condition_valid(vcpu)) { >> -kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); >> -return 1; >> -} >> - >> -exit_handler = kvm_get_exit_handler(vcpu); >> - >> -return exit_handler(vcpu, run); >> +return handle_trap_exceptions(vcpu, run); >> case ARM_EXCEPTION_HYP_GONE: >> /* >> * EL2 has been reset to the hyp-stub. This happens when a guest >> -- >> 2.14.1 >> > > Thanks, > -Christoffer -- Alex Bennée
Re: [PATCH v1 2/2] kvm: arm64: handle single-step of userspace mmio instructions
Marc Zyngier writes: > On 06/10/17 13:37, Marc Zyngier wrote: >> On 06/10/17 12:39, Alex Bennée wrote: >>> The system state of KVM when using userspace emulation is not complete >>> until we return into KVM_RUN. To handle mmio related updates we wait >>> until they have been committed and then schedule our KVM_EXIT_DEBUG. >>> >>> I've introduced a new function kvm_arm_maybe_return_debug() to wrap up >>> the differences between arm/arm64 which is currently null for arm. >>> >>> Signed-off-by: Alex Bennée >>> --- >>> arch/arm/include/asm/kvm_host.h | 2 ++ >>> arch/arm64/include/asm/kvm_host.h | 1 + >>> arch/arm64/kvm/debug.c| 21 + >>> arch/arm64/kvm/handle_exit.c | 9 +++-- >>> virt/kvm/arm/arm.c| 2 +- >>> virt/kvm/arm/mmio.c | 3 ++- >>> 6 files changed, 30 insertions(+), 8 deletions(-) >>> >>> diff --git a/arch/arm/include/asm/kvm_host.h >>> b/arch/arm/include/asm/kvm_host.h >>> index 4a879f6ff13b..aec943f6d123 100644 >>> --- a/arch/arm/include/asm/kvm_host.h >>> +++ b/arch/arm/include/asm/kvm_host.h >>> @@ -285,6 +285,8 @@ static inline void kvm_arm_init_debug(void) {} >>> static inline void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) {} >>> static inline void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) {} >>> static inline void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu) {} >>> +static inline int kvm_arm_maybe_return_debug(struct kvm_vcpu *vcpu, >>> + struct kvm_run *run) {} >>> >>> int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu, >>>struct kvm_device_attr *attr); >>> diff --git a/arch/arm64/include/asm/kvm_host.h >>> b/arch/arm64/include/asm/kvm_host.h >>> index e923b58606e2..fa67d21662f6 100644 >>> --- a/arch/arm64/include/asm/kvm_host.h >>> +++ b/arch/arm64/include/asm/kvm_host.h >>> @@ -369,6 +369,7 @@ void kvm_arm_init_debug(void); >>> void kvm_arm_setup_debug(struct kvm_vcpu *vcpu); >>> void kvm_arm_clear_debug(struct kvm_vcpu *vcpu); >>> void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu); >>> +int kvm_arm_maybe_return_debug(struct kvm_vcpu *vcpu, struct kvm_run >>> *run); >>> int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu, >>>struct kvm_device_attr *attr); >>> int kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu, >>> diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c >>> index dbadfaf850a7..a10a18c55c87 100644 >>> --- a/arch/arm64/kvm/debug.c >>> +++ b/arch/arm64/kvm/debug.c >>> @@ -221,3 +221,24 @@ void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) >>> } >>> } >>> } >>> + >>> + >>> +/* >>> + * When KVM has successfully emulated the instruction we might want to >>> + * return we a KVM_EXIT_DEBUG. We can only do this once the emulation >>> + * is complete though so for userspace emulations we have to wait >>> + * until we have re-entered KVM. >>> + * >>> + * Return > 0 to return to guest, 0 (and set exit_reason) on proper >>> + * exit to userspace. >>> + */ >>> + >>> +int kvm_arm_maybe_return_debug(struct kvm_vcpu *vcpu, struct kvm_run *run) >>> +{ >>> + if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) { >>> + run->exit_reason = KVM_EXIT_DEBUG; >>> + run->debug.arch.hsr = ESR_ELx_EC_SOFTSTP_LOW << >>> ESR_ELx_EC_SHIFT; >>> + return 0; >>> + } >>> + return 1; >>> +} >>> diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c >>> index c918d291cb58..7b04f59217bf 100644 >>> --- a/arch/arm64/kvm/handle_exit.c >>> +++ b/arch/arm64/kvm/handle_exit.c >>> @@ -202,13 +202,10 @@ static int handle_trap_exceptions(struct kvm_vcpu >>> *vcpu, struct kvm_run *run) >>> handled = exit_handler(vcpu, run); >>> } >>> >>> - if (handled && (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)) { >>> - handled = 0; >>> - run->exit_reason = KVM_EXIT_DEBUG; >>> - run->debug.arch.hsr = ESR_ELx_EC_SOFTSTP_LOW << >>> ESR_ELx_EC_SHIFT; >>> - } >>> + if (handled) >>> + return kvm_arm_maybe_return_d
Re: [PATCH v1 2/2] kvm: arm64: handle single-step of userspace mmio instructions
Julien Thierry writes: > On 06/10/17 12:39, Alex Bennée wrote: >> The system state of KVM when using userspace emulation is not complete >> until we return into KVM_RUN. To handle mmio related updates we wait >> until they have been committed and then schedule our KVM_EXIT_DEBUG. >> >> I've introduced a new function kvm_arm_maybe_return_debug() to wrap up >> the differences between arm/arm64 which is currently null for arm. >> >> Signed-off-by: Alex Bennée >> --- >> arch/arm/include/asm/kvm_host.h | 2 ++ >> arch/arm64/include/asm/kvm_host.h | 1 + >> arch/arm64/kvm/debug.c| 21 + >> arch/arm64/kvm/handle_exit.c | 9 +++-- >> virt/kvm/arm/arm.c| 2 +- >> virt/kvm/arm/mmio.c | 3 ++- >> 6 files changed, 30 insertions(+), 8 deletions(-) >> >> diff --git a/arch/arm/include/asm/kvm_host.h >> b/arch/arm/include/asm/kvm_host.h >> index 4a879f6ff13b..aec943f6d123 100644 >> --- a/arch/arm/include/asm/kvm_host.h >> +++ b/arch/arm/include/asm/kvm_host.h >> @@ -285,6 +285,8 @@ static inline void kvm_arm_init_debug(void) {} >> static inline void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) {} >> static inline void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) {} >> static inline void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu) {} >> +static inline int kvm_arm_maybe_return_debug(struct kvm_vcpu *vcpu, >> +struct kvm_run *run) {} >> > > This function should return 1. So I did ponder making this a bool, returning true if we need to exit and testing in v/k/a/arm.c exit leg rather than in the mmio handler. At the moment it mirrors the existing exit logic which follows -1 err, 0 return, >0 handled. But as I mentioned in the cover letter this fell down a bit when dealing with the mmio case. > >> int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu, >> struct kvm_device_attr *attr); >> diff --git a/arch/arm64/include/asm/kvm_host.h >> b/arch/arm64/include/asm/kvm_host.h >> index e923b58606e2..fa67d21662f6 100644 >> --- a/arch/arm64/include/asm/kvm_host.h >> +++ b/arch/arm64/include/asm/kvm_host.h >> @@ -369,6 +369,7 @@ void kvm_arm_init_debug(void); >> void kvm_arm_setup_debug(struct kvm_vcpu *vcpu); >> void kvm_arm_clear_debug(struct kvm_vcpu *vcpu); >> void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu); >> +int kvm_arm_maybe_return_debug(struct kvm_vcpu *vcpu, struct kvm_run *run); > > I feel the name could be a little bit more explicit: > > kvm_arm_trap_need_step_debug, kvm_arm_trap_step_return_debug, > kvm_arm_trap_need_return_debug. I wanted to keep the debug suffix so that's fine although I'm not so sure trap is correct because on the tail end of mmio emulation are we still trapping? Maybe kvm_arm_step_emulated_debug? > At least, I think it would be nice that the name reflect that this > check is meant for emulated instructions. > > Otherwise: > > Reviewed-by: Julien Thierry > > Thanks, -- Alex Bennée
[PATCH v1 1/2] KVM: arm64: handle single-stepping trapped instructions
If we are using guest debug to single-step the guest we need to ensure we exit after emulating the instruction. This only affects instructions completely emulated by the kernel. For userspace emulated instructions we need to exit and return to complete the emulation. We fake debug.arch.hsr to contain ESR_ELx_EC_SOFTSTP_LOW so QEMU knows it was a single-step event (and without altering the userspace ABI). Signed-off-by: Alex Bennée --- arch/arm64/kvm/handle_exit.c | 48 +++- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 7debb74843a0..c918d291cb58 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -178,6 +178,39 @@ static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu) return arm_exit_handlers[hsr_ec]; } +/* + * When handling traps we need to ensure exit the guest if we + * completely emulated the instruction while single-stepping. Stuff to + * be emulated in userspace needs to complete that first. + */ + +static int handle_trap_exceptions(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + int handled; + + /* +* See ARM ARM B1.14.1: "Hyp traps on instructions +* that fail their condition code check" +*/ + if (!kvm_condition_valid(vcpu)) { + kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); + handled = 1; + } else { + exit_handle_fn exit_handler; + + exit_handler = kvm_get_exit_handler(vcpu); + handled = exit_handler(vcpu, run); + } + + if (handled && (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)) { + handled = 0; + run->exit_reason = KVM_EXIT_DEBUG; + run->debug.arch.hsr = ESR_ELx_EC_SOFTSTP_LOW << ESR_ELx_EC_SHIFT; + } + + return handled; +} + /* * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on * proper exit to userspace. @@ -185,8 +218,6 @@ static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu) int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, int exception_index) { - exit_handle_fn exit_handler; - if (ARM_SERROR_PENDING(exception_index)) { u8 hsr_ec = ESR_ELx_EC(kvm_vcpu_get_hsr(vcpu)); @@ -214,18 +245,7 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, kvm_inject_vabt(vcpu); return 1; case ARM_EXCEPTION_TRAP: - /* -* See ARM ARM B1.14.1: "Hyp traps on instructions -* that fail their condition code check" -*/ - if (!kvm_condition_valid(vcpu)) { - kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); - return 1; - } - - exit_handler = kvm_get_exit_handler(vcpu); - - return exit_handler(vcpu, run); + return handle_trap_exceptions(vcpu, run); case ARM_EXCEPTION_HYP_GONE: /* * EL2 has been reset to the hyp-stub. This happens when a guest -- 2.14.1
[PATCH v1 2/2] kvm: arm64: handle single-step of userspace mmio instructions
The system state of KVM when using userspace emulation is not complete until we return into KVM_RUN. To handle mmio related updates we wait until they have been committed and then schedule our KVM_EXIT_DEBUG. I've introduced a new function kvm_arm_maybe_return_debug() to wrap up the differences between arm/arm64 which is currently null for arm. Signed-off-by: Alex Bennée --- arch/arm/include/asm/kvm_host.h | 2 ++ arch/arm64/include/asm/kvm_host.h | 1 + arch/arm64/kvm/debug.c| 21 + arch/arm64/kvm/handle_exit.c | 9 +++-- virt/kvm/arm/arm.c| 2 +- virt/kvm/arm/mmio.c | 3 ++- 6 files changed, 30 insertions(+), 8 deletions(-) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 4a879f6ff13b..aec943f6d123 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -285,6 +285,8 @@ static inline void kvm_arm_init_debug(void) {} static inline void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) {} static inline void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) {} static inline void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu) {} +static inline int kvm_arm_maybe_return_debug(struct kvm_vcpu *vcpu, + struct kvm_run *run) {} int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr); diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index e923b58606e2..fa67d21662f6 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -369,6 +369,7 @@ void kvm_arm_init_debug(void); void kvm_arm_setup_debug(struct kvm_vcpu *vcpu); void kvm_arm_clear_debug(struct kvm_vcpu *vcpu); void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu); +int kvm_arm_maybe_return_debug(struct kvm_vcpu *vcpu, struct kvm_run *run); int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr); int kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu, diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index dbadfaf850a7..a10a18c55c87 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -221,3 +221,24 @@ void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) } } } + + +/* + * When KVM has successfully emulated the instruction we might want to + * return we a KVM_EXIT_DEBUG. We can only do this once the emulation + * is complete though so for userspace emulations we have to wait + * until we have re-entered KVM. + * + * Return > 0 to return to guest, 0 (and set exit_reason) on proper + * exit to userspace. + */ + +int kvm_arm_maybe_return_debug(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) { + run->exit_reason = KVM_EXIT_DEBUG; + run->debug.arch.hsr = ESR_ELx_EC_SOFTSTP_LOW << ESR_ELx_EC_SHIFT; + return 0; + } + return 1; +} diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index c918d291cb58..7b04f59217bf 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -202,13 +202,10 @@ static int handle_trap_exceptions(struct kvm_vcpu *vcpu, struct kvm_run *run) handled = exit_handler(vcpu, run); } - if (handled && (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)) { - handled = 0; - run->exit_reason = KVM_EXIT_DEBUG; - run->debug.arch.hsr = ESR_ELx_EC_SOFTSTP_LOW << ESR_ELx_EC_SHIFT; - } + if (handled) + return kvm_arm_maybe_return_debug(vcpu, run); - return handled; + return 0; } /* diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index b9f68e4add71..3d28fe2daa26 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c @@ -623,7 +623,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) if (run->exit_reason == KVM_EXIT_MMIO) { ret = kvm_handle_mmio_return(vcpu, vcpu->run); - if (ret) + if (ret < 1) return ret; } diff --git a/virt/kvm/arm/mmio.c b/virt/kvm/arm/mmio.c index b6e715fd3c90..e43e3bd6222f 100644 --- a/virt/kvm/arm/mmio.c +++ b/virt/kvm/arm/mmio.c @@ -117,7 +117,8 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run) vcpu_set_reg(vcpu, vcpu->arch.mmio_decode.rt, data); } - return 0; + /* If debugging in effect we may need to return now */ + return kvm_arm_maybe_return_debug(vcpu, run); } static int decode_hsr(struct kvm_vcpu *vcpu, bool *is_write, int *len) -- 2.14.1
[PATCH v2 2/2] KVM: arm: rename pm_fake handler to trap_raz_wi
From: Zhichao Huang pm_fake doesn't quite describe what the handler does (ignoring writes and returning 0 for reads). As we're about to use it (a lot) in a different context, rename it with a (admitedly cryptic) name that make sense for all users. Signed-off-by: Zhichao Huang Reviewed-by: Alex Bennee Acked-by: Christoffer Dall Acked-by: Marc Zyngier Signed-off-by: Alex Bennée --- v2: - fix minor merge conflicts - add maz a-b --- arch/arm/kvm/coproc.c | 32 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c index c3ed6bd5ddf3..31bd9bb0b765 100644 --- a/arch/arm/kvm/coproc.c +++ b/arch/arm/kvm/coproc.c @@ -260,7 +260,7 @@ static bool access_gic_sre(struct kvm_vcpu *vcpu, * must always support PMCCNTR (the cycle counter): we just RAZ/WI for * all PM registers, which doesn't crash the guest kernel at least. */ -static bool pm_fake(struct kvm_vcpu *vcpu, +static bool trap_raz_wi(struct kvm_vcpu *vcpu, const struct coproc_params *p, const struct coproc_reg *r) { @@ -270,19 +270,19 @@ static bool pm_fake(struct kvm_vcpu *vcpu, return read_zero(vcpu, p); } -#define access_pmcr pm_fake -#define access_pmcntenset pm_fake -#define access_pmcntenclr pm_fake -#define access_pmovsr pm_fake -#define access_pmselr pm_fake -#define access_pmceid0 pm_fake -#define access_pmceid1 pm_fake -#define access_pmccntr pm_fake -#define access_pmxevtyper pm_fake -#define access_pmxevcntr pm_fake -#define access_pmuserenr pm_fake -#define access_pmintenset pm_fake -#define access_pmintenclr pm_fake +#define access_pmcr trap_raz_wi +#define access_pmcntenset trap_raz_wi +#define access_pmcntenclr trap_raz_wi +#define access_pmovsr trap_raz_wi +#define access_pmselr trap_raz_wi +#define access_pmceid0 trap_raz_wi +#define access_pmceid1 trap_raz_wi +#define access_pmccntr trap_raz_wi +#define access_pmxevtyper trap_raz_wi +#define access_pmxevcntr trap_raz_wi +#define access_pmuserenr trap_raz_wi +#define access_pmintenset trap_raz_wi +#define access_pmintenclr trap_raz_wi /* Architected CP15 registers. * CRn denotes the primary register number, but is copied to the CRm in the @@ -547,7 +547,7 @@ int kvm_handle_cp14_64(struct kvm_vcpu *vcpu, struct kvm_run *run) struct coproc_params params = decode_64bit_hsr(vcpu); /* raz_wi cp14 */ - pm_fake(vcpu, ¶ms, NULL); + trap_raz_wi(vcpu, ¶ms, NULL); /* handled */ kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); @@ -602,7 +602,7 @@ int kvm_handle_cp14_32(struct kvm_vcpu *vcpu, struct kvm_run *run) struct coproc_params params = decode_32bit_hsr(vcpu); /* raz_wi cp14 */ - pm_fake(vcpu, ¶ms, NULL); + trap_raz_wi(vcpu, ¶ms, NULL); /* handled */ kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); -- 2.11.0
[PATCH v2 1/2] KVM: arm: plug potential guest hardware debug leakage
From: Zhichao Huang Hardware debugging in guests is not intercepted currently, it means that a malicious guest can bring down the entire machine by writing to the debug registers. This patch enable trapping of all debug registers, preventing the guests to access the debug registers. This includes access to the debug mode(DBGDSCR) in the guest world all the time which could otherwise mess with the host state. Reads return 0 and writes are ignored (RAZ_WI). The result is the guest cannot detect any working hardware based debug support. As debug exceptions are still routed to the guest normal debug using software based breakpoints still works. To support debugging using hardware registers we need to implement a debug register aware world switch as well as special trapping for registers that may affect the host state. Signed-off-by: Zhichao Huang Signed-off-by: Alex Bennée --- ajb v2: - don't (void) unused return value - fix some 0/1 bool usage - further re-factor to avoid hacky if (cp15) in trap path ajb v1: - convert to C world switch - reword commit message --- arch/arm/include/asm/kvm_coproc.h | 3 +- arch/arm/kvm/coproc.c | 77 ++- arch/arm/kvm/handle_exit.c| 4 +- arch/arm/kvm/hyp/switch.c | 4 +- 4 files changed, 66 insertions(+), 22 deletions(-) diff --git a/arch/arm/include/asm/kvm_coproc.h b/arch/arm/include/asm/kvm_coproc.h index 4917c2f7e459..e74ab0fbab79 100644 --- a/arch/arm/include/asm/kvm_coproc.h +++ b/arch/arm/include/asm/kvm_coproc.h @@ -31,7 +31,8 @@ void kvm_register_target_coproc_table(struct kvm_coproc_target_table *table); int kvm_handle_cp10_id(struct kvm_vcpu *vcpu, struct kvm_run *run); int kvm_handle_cp_0_13_access(struct kvm_vcpu *vcpu, struct kvm_run *run); int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run); -int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run); +int kvm_handle_cp14_32(struct kvm_vcpu *vcpu, struct kvm_run *run); +int kvm_handle_cp14_64(struct kvm_vcpu *vcpu, struct kvm_run *run); int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run); int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run); diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c index 3e5e4194ef86..c3ed6bd5ddf3 100644 --- a/arch/arm/kvm/coproc.c +++ b/arch/arm/kvm/coproc.c @@ -93,12 +93,6 @@ int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run) return 1; } -int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run) -{ - kvm_inject_undefined(vcpu); - return 1; -} - static void reset_mpidr(struct kvm_vcpu *vcpu, const struct coproc_reg *r) { /* @@ -514,12 +508,7 @@ static int emulate_cp15(struct kvm_vcpu *vcpu, return 1; } -/** - * kvm_handle_cp15_64 -- handles a mrrc/mcrr trap on a guest CP15 access - * @vcpu: The VCPU pointer - * @run: The kvm_run struct - */ -int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run) +static struct coproc_params decode_64bit_hsr(struct kvm_vcpu *vcpu) { struct coproc_params params; @@ -533,9 +522,38 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run) params.Rt2 = (kvm_vcpu_get_hsr(vcpu) >> 10) & 0xf; params.CRm = 0; + return params; +} + +/** + * kvm_handle_cp15_64 -- handles a mrrc/mcrr trap on a guest CP15 access + * @vcpu: The VCPU pointer + * @run: The kvm_run struct + */ +int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + struct coproc_params params = decode_64bit_hsr(vcpu); + return emulate_cp15(vcpu, ¶ms); } +/** + * kvm_handle_cp14_64 -- handles a mrrc/mcrr trap on a guest CP14 access + * @vcpu: The VCPU pointer + * @run: The kvm_run struct + */ +int kvm_handle_cp14_64(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + struct coproc_params params = decode_64bit_hsr(vcpu); + + /* raz_wi cp14 */ + pm_fake(vcpu, ¶ms, NULL); + + /* handled */ + kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); + return 1; +} + static void reset_coproc_regs(struct kvm_vcpu *vcpu, const struct coproc_reg *table, size_t num) { @@ -546,12 +564,7 @@ static void reset_coproc_regs(struct kvm_vcpu *vcpu, table[i].reset(vcpu, &table[i]); } -/** - * kvm_handle_cp15_32 -- handles a mrc/mcr trap on a guest CP15 access - * @vcpu: The VCPU pointer - * @run: The kvm_run struct - */ -int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run) +static struct coproc_params decode_32bit_hsr(struct kvm_vcpu *vcpu) { struct coproc_params params; @@ -565,9 +578,37 @@ int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run) params.Op2 = (kvm_vcpu_get_hsr(vcpu) >> 17) & 0x7; params.Rt2 = 0; + return params; +} + +/** + * kvm_handle_cp15_32 -- handles a mrc/mcr trap on a guest CP
Re: [PATCH v1 1/2] KVM: arm: plug guest debug exploit
Marc Zyngier writes: > Hi Alex, > > On 10/05/17 18:01, Alex Bennée wrote: >> From: Zhichao Huang >> >> Hardware debugging in guests is not intercepted currently, it means >> that a malicious guest can bring down the entire machine by writing >> to the debug registers. >> >> This patch enable trapping of all debug registers, preventing the >> guests to access the debug registers. This includes access to the >> debug mode(DBGDSCR) in the guest world all the time which could >> otherwise mess with the host state. Reads return 0 and writes are >> ignored. >> >> The result is the guest cannot detect any working hardware based debug >> support. As debug exceptions are still routed to the guest normal >> debug using software based breakpoints still works. >> >> To support debugging using hardware registers we need to implement a >> debug register aware world switch as well as special trapping for >> registers that may affect the host state. >> >> Signed-off-by: Zhichao Huang >> Signed-off-by: Alex Bennée >> >> --- >> ajb: >> - convert to C world switch >> - reword commit message >> --- >> arch/arm/include/asm/kvm_coproc.h | 3 +- >> arch/arm/kvm/coproc.c | 82 >> +-- >> arch/arm/kvm/handle_exit.c| 4 +- >> arch/arm/kvm/hyp/switch.c | 4 +- >> 4 files changed, 69 insertions(+), 24 deletions(-) >> >> diff --git a/arch/arm/include/asm/kvm_coproc.h >> b/arch/arm/include/asm/kvm_coproc.h >> index 4917c2f7e459..e74ab0fbab79 100644 >> --- a/arch/arm/include/asm/kvm_coproc.h >> +++ b/arch/arm/include/asm/kvm_coproc.h >> @@ -31,7 +31,8 @@ void kvm_register_target_coproc_table(struct >> kvm_coproc_target_table *table); >> int kvm_handle_cp10_id(struct kvm_vcpu *vcpu, struct kvm_run *run); >> int kvm_handle_cp_0_13_access(struct kvm_vcpu *vcpu, struct kvm_run *run); >> int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run); >> -int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run); >> +int kvm_handle_cp14_32(struct kvm_vcpu *vcpu, struct kvm_run *run); >> +int kvm_handle_cp14_64(struct kvm_vcpu *vcpu, struct kvm_run *run); >> int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run); >> int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run); >> >> diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c >> index 3e5e4194ef86..b2053393bb1f 100644 >> --- a/arch/arm/kvm/coproc.c >> +++ b/arch/arm/kvm/coproc.c >> @@ -93,12 +93,6 @@ int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, >> struct kvm_run *run) >> return 1; >> } >> >> -int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run) >> -{ >> -kvm_inject_undefined(vcpu); >> -return 1; >> -} >> - >> static void reset_mpidr(struct kvm_vcpu *vcpu, const struct coproc_reg *r) >> { >> /* >> @@ -514,12 +508,8 @@ static int emulate_cp15(struct kvm_vcpu *vcpu, >> return 1; >> } >> >> -/** >> - * kvm_handle_cp15_64 -- handles a mrrc/mcrr trap on a guest CP15 access >> - * @vcpu: The VCPU pointer >> - * @run: The kvm_run struct >> - */ >> -int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run) >> +static int kvm_handle_cp_64(struct kvm_vcpu *vcpu, struct kvm_run *run, >> +bool cp15) >> { >> struct coproc_params params; >> >> @@ -533,7 +523,35 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct >> kvm_run *run) >> params.Rt2 = (kvm_vcpu_get_hsr(vcpu) >> 10) & 0xf; >> params.CRm = 0; >> >> -return emulate_cp15(vcpu, ¶ms); >> +if (cp15) >> +return emulate_cp15(vcpu, ¶ms); >> + >> +/* raz_wi cp14 */ >> +(void)pm_fake(vcpu, ¶ms, NULL); > > Why this (void) cast? I guess a super picky compiler could complain about throwing away a return value? Mine didn't do I've removed it. > >> + >> +/* handled */ >> +kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); >> +return 1; >> +} >> + >> +/** >> + * kvm_handle_cp15_64 -- handles a mrrc/mcrr trap on a guest CP15 access >> + * @vcpu: The VCPU pointer >> + * @run: The kvm_run struct >> + */ >> +int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run) >> +{ >> +return kvm_handle_cp_64(vcpu, run, 1); > > true instead of 1? fixed > >> +} >> + &
[PATCH v1 2/2] KVM: arm: rename pm_fake handler to trap_raz_wi
From: Zhichao Huang pm_fake doesn't quite describe what the handler does (ignoring writes and returning 0 for reads). As we're about to use it (a lot) in a different context, rename it with a (admitedly cryptic) name that make sense for all users. Signed-off-by: Zhichao Huang Reviewed-by: Alex Bennee Acked-by: Christoffer Dall Signed-off-by: Alex Bennée --- arch/arm/kvm/coproc.c | 32 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c index b2053393bb1f..6919363ce7cc 100644 --- a/arch/arm/kvm/coproc.c +++ b/arch/arm/kvm/coproc.c @@ -260,7 +260,7 @@ static bool access_gic_sre(struct kvm_vcpu *vcpu, * must always support PMCCNTR (the cycle counter): we just RAZ/WI for * all PM registers, which doesn't crash the guest kernel at least. */ -static bool pm_fake(struct kvm_vcpu *vcpu, +static bool trap_raz_wi(struct kvm_vcpu *vcpu, const struct coproc_params *p, const struct coproc_reg *r) { @@ -270,19 +270,19 @@ static bool pm_fake(struct kvm_vcpu *vcpu, return read_zero(vcpu, p); } -#define access_pmcr pm_fake -#define access_pmcntenset pm_fake -#define access_pmcntenclr pm_fake -#define access_pmovsr pm_fake -#define access_pmselr pm_fake -#define access_pmceid0 pm_fake -#define access_pmceid1 pm_fake -#define access_pmccntr pm_fake -#define access_pmxevtyper pm_fake -#define access_pmxevcntr pm_fake -#define access_pmuserenr pm_fake -#define access_pmintenset pm_fake -#define access_pmintenclr pm_fake +#define access_pmcr trap_raz_wi +#define access_pmcntenset trap_raz_wi +#define access_pmcntenclr trap_raz_wi +#define access_pmovsr trap_raz_wi +#define access_pmselr trap_raz_wi +#define access_pmceid0 trap_raz_wi +#define access_pmceid1 trap_raz_wi +#define access_pmccntr trap_raz_wi +#define access_pmxevtyper trap_raz_wi +#define access_pmxevcntr trap_raz_wi +#define access_pmuserenr trap_raz_wi +#define access_pmintenset trap_raz_wi +#define access_pmintenclr trap_raz_wi /* Architected CP15 registers. * CRn denotes the primary register number, but is copied to the CRm in the @@ -527,7 +527,7 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu, struct kvm_run *run, return emulate_cp15(vcpu, ¶ms); /* raz_wi cp14 */ - (void)pm_fake(vcpu, ¶ms, NULL); + (void)trap_raz_wi(vcpu, ¶ms, NULL); /* handled */ kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); @@ -583,7 +583,7 @@ static int kvm_handle_cp_32(struct kvm_vcpu *vcpu, struct kvm_run *run, return emulate_cp15(vcpu, ¶ms); /* raz_wi cp14 */ - (void)pm_fake(vcpu, ¶ms, NULL); + (void)trap_raz_wi(vcpu, ¶ms, NULL); /* handled */ kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); -- 2.11.0
[PATCH v1 1/2] KVM: arm: plug guest debug exploit
From: Zhichao Huang Hardware debugging in guests is not intercepted currently, it means that a malicious guest can bring down the entire machine by writing to the debug registers. This patch enable trapping of all debug registers, preventing the guests to access the debug registers. This includes access to the debug mode(DBGDSCR) in the guest world all the time which could otherwise mess with the host state. Reads return 0 and writes are ignored. The result is the guest cannot detect any working hardware based debug support. As debug exceptions are still routed to the guest normal debug using software based breakpoints still works. To support debugging using hardware registers we need to implement a debug register aware world switch as well as special trapping for registers that may affect the host state. Signed-off-by: Zhichao Huang Signed-off-by: Alex Bennée --- ajb: - convert to C world switch - reword commit message --- arch/arm/include/asm/kvm_coproc.h | 3 +- arch/arm/kvm/coproc.c | 82 +-- arch/arm/kvm/handle_exit.c| 4 +- arch/arm/kvm/hyp/switch.c | 4 +- 4 files changed, 69 insertions(+), 24 deletions(-) diff --git a/arch/arm/include/asm/kvm_coproc.h b/arch/arm/include/asm/kvm_coproc.h index 4917c2f7e459..e74ab0fbab79 100644 --- a/arch/arm/include/asm/kvm_coproc.h +++ b/arch/arm/include/asm/kvm_coproc.h @@ -31,7 +31,8 @@ void kvm_register_target_coproc_table(struct kvm_coproc_target_table *table); int kvm_handle_cp10_id(struct kvm_vcpu *vcpu, struct kvm_run *run); int kvm_handle_cp_0_13_access(struct kvm_vcpu *vcpu, struct kvm_run *run); int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run); -int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run); +int kvm_handle_cp14_32(struct kvm_vcpu *vcpu, struct kvm_run *run); +int kvm_handle_cp14_64(struct kvm_vcpu *vcpu, struct kvm_run *run); int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run); int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run); diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c index 3e5e4194ef86..b2053393bb1f 100644 --- a/arch/arm/kvm/coproc.c +++ b/arch/arm/kvm/coproc.c @@ -93,12 +93,6 @@ int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run) return 1; } -int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run) -{ - kvm_inject_undefined(vcpu); - return 1; -} - static void reset_mpidr(struct kvm_vcpu *vcpu, const struct coproc_reg *r) { /* @@ -514,12 +508,8 @@ static int emulate_cp15(struct kvm_vcpu *vcpu, return 1; } -/** - * kvm_handle_cp15_64 -- handles a mrrc/mcrr trap on a guest CP15 access - * @vcpu: The VCPU pointer - * @run: The kvm_run struct - */ -int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run) +static int kvm_handle_cp_64(struct kvm_vcpu *vcpu, struct kvm_run *run, + bool cp15) { struct coproc_params params; @@ -533,7 +523,35 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run) params.Rt2 = (kvm_vcpu_get_hsr(vcpu) >> 10) & 0xf; params.CRm = 0; - return emulate_cp15(vcpu, ¶ms); + if (cp15) + return emulate_cp15(vcpu, ¶ms); + + /* raz_wi cp14 */ + (void)pm_fake(vcpu, ¶ms, NULL); + + /* handled */ + kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); + return 1; +} + +/** + * kvm_handle_cp15_64 -- handles a mrrc/mcrr trap on a guest CP15 access + * @vcpu: The VCPU pointer + * @run: The kvm_run struct + */ +int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + return kvm_handle_cp_64(vcpu, run, 1); +} + +/** + * kvm_handle_cp14_64 -- handles a mrrc/mcrr trap on a guest CP14 access + * @vcpu: The VCPU pointer + * @run: The kvm_run struct + */ +int kvm_handle_cp14_64(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + return kvm_handle_cp_64(vcpu, run, 0); } static void reset_coproc_regs(struct kvm_vcpu *vcpu, @@ -546,12 +564,8 @@ static void reset_coproc_regs(struct kvm_vcpu *vcpu, table[i].reset(vcpu, &table[i]); } -/** - * kvm_handle_cp15_32 -- handles a mrc/mcr trap on a guest CP15 access - * @vcpu: The VCPU pointer - * @run: The kvm_run struct - */ -int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run) +static int kvm_handle_cp_32(struct kvm_vcpu *vcpu, struct kvm_run *run, + bool cp15) { struct coproc_params params; @@ -565,7 +579,35 @@ int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run) params.Op2 = (kvm_vcpu_get_hsr(vcpu) >> 17) & 0x7; params.Rt2 = 0; - return emulate_cp15(vcpu, ¶ms); + if (cp15) + return emulate_cp15(vcpu, ¶ms); + + /* raz_wi cp14 */ + (void)pm_fake(vcpu, ¶ms, NULL); + + /* handled */ +
Re: [PATCH] binfmt_misc: allow selecting the interpreter based on xattr keywords
Carlos O'Donell writes: > On 08/26/2016 10:55 AM, Florian Weimer wrote: >> On 08/25/2016 06:15 PM, James Bottomley wrote: >>> On Sun, 2016-08-21 at 21:01 -0700, Josh Max wrote: > > This ignores the fact that the alternate loader also needs to have > it's own ldconfig cache, implementation-dependent lookup paths etc, > all of which have to be keyed off the xattr keyword specified dynamic > loader. All of that is tractable though and can be done in userspace > keyed from the selected dynamic loader. Buy why? Why not use a mount > namespace and different loader e.g. lxc, docker, etc, or specify a > loader that is a wrapper and does this for you? Is binfmt_misc actually containerise-able yet? At the moment when using qemu-user inside a docker container I still have to ensure the root binfmt_misc points to the same location as I place qemu-user in the docker container. > > I'm not convinced this is a good idea, but I'm open to learning about > more use cases. -- Alex Bennée
Re: [PATCH v15 00/10] arm64: Add kernel probes (kprobes) support
Marc Zyngier writes: > On 15/07/16 08:50, Catalin Marinas wrote: >> On Thu, Jul 14, 2016 at 01:09:08PM -0400, William Cohen wrote: >>> On 07/14/2016 12:22 PM, Catalin Marinas wrote: >>>> On Fri, Jul 08, 2016 at 12:35:44PM -0400, David Long wrote: >>>>> David A. Long (3): >>>>> arm64: Add HAVE_REGS_AND_STACK_ACCESS_API feature >>>>> arm64: Add more test functions to insn.c >>>>> arm64: add conditional instruction simulation support >>>>> >>>>> Pratyush Anand (2): >>>>> arm64: Blacklist non-kprobe-able symbol >>>>> arm64: Treat all entry code as non-kprobe-able >>>>> >>>>> Sandeepa Prabhu (4): >>>>> arm64: Kprobes with single stepping support >>>>> arm64: kprobes instruction simulation support >>>>> arm64: Add kernel return probes support (kretprobes) >>>>> kprobes: Add arm64 case in kprobe example module >>>>> >>>>> William Cohen (1): >>>>> arm64: Add trampoline code for kretprobes >>>> >>>> I applied these patches on top of the arm64 for-next/core branch an >>>> tried to run the resulting kernel in a guest (on a Juno platform using >>>> both kvmtool and qemu) with KPROBES_SANITY_TEST enabled. Unfortunately, >>>> the kernel fails to boot with lots of "Unexpected kernel single-step >>>> exception at EL1". >>>> >>>> Did you manage to run Kprobes in a guest before? >>> >>> I ran the systemtap testsuite several times on a physical machine >>> running a kernel with the kprobe v15 patches without problem. >>> Shouldn't the guest machine behave in the same manner as a host >>> machine for single stepping and exception handling? If the guest >>> machine is failing, wouldn't that suggest there is a problem with the >>> KVM handling of single stepping for guests? >> >> It didn't fail for me on the host either. What's strange is that on some >> occasions even the guest managed to get to a prompt. I'll do more tests >> today on different CPU configurations, just to rule out potential >> hardware issues. If not hardware related, it's possible that the >> interaction with KVM doesn't work as expected, maybe the >> saving/restoring of the guest debug state loses information. > > Could well be the latter. I'll try to have a look, but Alex Bennée (on > cc) is our man when it comes to the KVM debug infrastructure. > > Alex, any chance you could try this and shed some light on it? Sure I'll have a look. There are problems with running gdb inside a guest while trying to debug from outside associated with single-stepping but none of this should get in the way if your not debugging the guest. Let me get my system spun up and see if I can reproduce. Shall I just apply this series on top of the current master? -- Alex Bennée
Re: [PATCH v4 00/23] arm64: Virtualization Host Extension support
Marc Zyngier writes: > ARMv8.1 comes with the "Virtualization Host Extension" (VHE for > short), which enables simpler support of Type-2 hypervisors. > > This extension allows the kernel to directly run at EL2, and > significantly reduces the number of system registers shared between > host and guest, reducing the overhead of virtualization. > > In order to have the same kernel binary running on all versions of the > architecture, this series makes heavy use of runtime code patching. > > The first 22 patches massage the KVM code to deal with VHE and enable > Linux to run at EL2. The last patch catches an ugly case when VHE > capable CPUs are paired with some of their less capable siblings. This > should never happen, but hey... > > I have deliberately left out some of the more "advanced" > optimizations, as they are likely to distract the reviewer from the > core infrastructure, which is what I care about at the moment. > > Note: GDB is currently busted on VHE systems, as it checks for version > 6 on the debug architecture, while VHE is version 7. The > binutils people are on the case. I assume you are talking about ptrace debug here rather than guest debug? Anyway from a cursory inspection I didn't see anything to worry about from the guest debug side which is unchanged. Acked-by: Alex Bennée > > This has been tested on the FVP_Base_SLV-V8-A model, and based on > v4.5-rc3 + kvmarm/master. I've put a branch out on: > > git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git > kvm-arm64/vhe > > * From v3: > - Cleaned debug handling after comments from Catalin > - Added missing barriers in the panic patch > - Collected Rb and Acks from Christoffer and Catalin > > * From v2: > - Added support for perf to count kernel events in EL2 > - Added support for EL2 breakpoints > - Moved the VTCR_EL2 setup from assembly to C > - Made the fault handling easier to understand (hopefuly) > - Plenty of smaller fixups > > * From v1: > - Full rewrite now that the World Switch is written in C code. > - Dropped the "early IRQ handling" for the moment. > > Marc Zyngier (23): > arm/arm64: KVM: Add hook for C-based stage2 init > arm64: KVM: Switch to C-based stage2 init > arm/arm64: Add new is_kernel_in_hyp_mode predicate > arm64: Allow the arch timer to use the HYP timer > arm64: Add ARM64_HAS_VIRT_HOST_EXTN feature > arm64: KVM: Skip HYP setup when already running in HYP > arm64: KVM: VHE: Patch out use of HVC > arm64: KVM: VHE: Patch out kern_hyp_va > arm64: KVM: VHE: Introduce unified system register accessors > arm64: KVM: VHE: Differenciate host/guest sysreg save/restore > arm64: KVM: VHE: Split save/restore of registers shared between guest > and host > arm64: KVM: VHE: Use unified system register accessors > arm64: KVM: VHE: Enable minimal sysreg save/restore > arm64: KVM: VHE: Make __fpsimd_enabled VHE aware > arm64: KVM: VHE: Implement VHE activate/deactivate_traps > arm64: KVM: VHE: Use unified sysreg accessors for timer > arm64: KVM: VHE: Add fpsimd enabling on guest access > arm64: KVM: VHE: Add alternative panic handling > arm64: KVM: Move most of the fault decoding to C > arm64: perf: Count EL2 events if the kernel is running in HYP > arm64: hw_breakpoint: Allow EL2 breakpoints if running in HYP > arm64: VHE: Add support for running Linux in EL2 mode > arm64: Panic when VHE and non VHE CPUs coexist > > arch/arm/include/asm/kvm_host.h| 4 + > arch/arm/include/asm/virt.h| 5 + > arch/arm/kvm/arm.c | 174 ++-- > arch/arm/kvm/mmu.c | 7 ++ > arch/arm64/Kconfig | 13 +++ > arch/arm64/include/asm/cpufeature.h| 3 +- > arch/arm64/include/asm/hw_breakpoint.h | 49 +--- > arch/arm64/include/asm/kvm_arm.h | 6 +- > arch/arm64/include/asm/kvm_asm.h | 2 + > arch/arm64/include/asm/kvm_emulate.h | 3 + > arch/arm64/include/asm/kvm_host.h | 6 + > arch/arm64/include/asm/kvm_mmu.h | 12 +- > arch/arm64/include/asm/virt.h | 27 + > arch/arm64/kernel/asm-offsets.c| 3 - > arch/arm64/kernel/cpufeature.c | 11 ++ > arch/arm64/kernel/head.S | 50 +++- > arch/arm64/kernel/perf_event.c | 14 ++- > arch/arm64/kernel/smp.c| 3 + > arch/arm64/kvm/hyp-init.S | 18 --- > arch/arm64/kvm/hyp.S | 7 ++ > arch/arm64/kvm/hyp/Makefile| 1 + > arch/arm64/kvm/hyp/entry.S | 6 + > arch/arm64/kvm/hyp/hyp-entry.S | 109 ++
Re: [PATCH 1/8] goldfish: refactor goldfish platform configs
Jin Qian writes: > From: Greg Hackmann > > On new virtual devices, the goldfish virtual bus can be replaced with > autoprobing infrastructure like Device Tree. Refactor the goldfish > kernel configs to better accommodate this. Should there be a header for this series? Does Google want to upstream the android pipe into mainline while we are still examining VirtIO alternatives? > > Move the goldfish platform into a menuconfig in the style of the chrome > platform, and separate the goldfish bus into its own config option. > > Signed-off-by: Greg Hackmann > (cherry picked from commit 711910868190ee3645c1c52701bdde87783f) > Signed-off-by: Jin Qian > --- > drivers/platform/Kconfig | 3 +-- > drivers/platform/goldfish/Kconfig | 18 ++ > drivers/platform/goldfish/Makefile | 2 +- > 3 files changed, 20 insertions(+), 3 deletions(-) > > diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig > index 0adccbf..c11db8b 100644 > --- a/drivers/platform/Kconfig > +++ b/drivers/platform/Kconfig > @@ -4,8 +4,7 @@ endif > if MIPS > source "drivers/platform/mips/Kconfig" > endif > -if GOLDFISH > + > source "drivers/platform/goldfish/Kconfig" > -endif > > source "drivers/platform/chrome/Kconfig" > diff --git a/drivers/platform/goldfish/Kconfig > b/drivers/platform/goldfish/Kconfig > index 635ef25..1ae3690 100644 > --- a/drivers/platform/goldfish/Kconfig > +++ b/drivers/platform/goldfish/Kconfig > @@ -1,5 +1,23 @@ > +menuconfig GOLDFISH > + bool "Platform support for Goldfish virtual devices" > + depends on X86_32 || X86_64 || ARM || ARM64 > + ---help--- > + Say Y here to get to see options for the Goldfish virtual platform. > + This option alone does not add any kernel code. > + > + Unless you are building for the Android Goldfish emulator say N here. > + > +if GOLDFISH > + > +config GOLDFISH_BUS > + tristate "Goldfish platform bus" > + ---help--- > + This is a virtual bus to host Goldfish Android Virtual Devices. > + > config GOLDFISH_PIPE > tristate "Goldfish virtual device for QEMU pipes" > ---help--- > This is a virtual device to drive the QEMU pipe interface used by > the Goldfish Android Virtual Device. > + > +endif # GOLDFISH > diff --git a/drivers/platform/goldfish/Makefile > b/drivers/platform/goldfish/Makefile > index a002239..d348712 100644 > --- a/drivers/platform/goldfish/Makefile > +++ b/drivers/platform/goldfish/Makefile > @@ -1,5 +1,5 @@ > # > # Makefile for Goldfish platform specific drivers > # > -obj-$(CONFIG_GOLDFISH) += pdev_bus.o > +obj-$(CONFIG_GOLDFISH_BUS) += pdev_bus.o > obj-$(CONFIG_GOLDFISH_PIPE) += goldfish_pipe.o > -- > 2.6.0.rc2.230.g3dd15c0 -- Alex Bennée -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [RFC PATCH v4 1/3] tracing/events: Fix wrong sample output by storing array length instead of size
Steven Rostedt writes: > On Fri, 17 Jul 2015 10:32:15 -0400 > Steven Rostedt wrote: > > >> This change affects all callers of dymanic_array, not just bitmasks. >> >> >__data_size += __item_length; >> > >> > #undef __string >> >> BTW, if I revert commit ac01ce1410fc2 "tracing: Make >> ftrace_print_array_seq compute buf_len" it works again. >> >> I'm going to look into this some more, and maybe the answer is to go >> back and just pass in buffer length here. I can't see what was broken >> before that change. > > OK, the print_array() code is already being used by the thermal events > and can't be changed. But we can't make the proposed change because > that changes the user interface. > > What we can change is the sample code! > > -- Steve > > From 95de1e9721a2f9d05831a53d228e181a33001c55 Mon Sep 17 00:00:00 2001 > From: "Steven Rostedt (Red Hat)" > Date: Fri, 17 Jul 2015 14:03:26 -0400 > Subject: [PATCH] tracing: Fix sample output of dynamic arrays > > He Kuang noticed that the trace event samples for arrays was broken: > > "The output result of trace_foo_bar event in traceevent samples is > wrong. This problem can be reproduced as following: > > (Build kernel with SAMPLE_TRACE_EVENTS=m) > > $ insmod trace-events-sample.ko > > $ echo 1 > /sys/kernel/debug/tracing/events/sample-trace/foo_bar/enable > > $ cat /sys/kernel/debug/tracing/trace > > event-sample-980 [000] 43.649559: foo_bar: foo hello 21 0x15 > BIT1|BIT3|0x10 {0x1,0x6f6f6e53,0xff007970,0x} Snoopy > ^^ > The array length is not right, should be {0x1}. > (,) > > event-sample-980 [000] 44.653827: foo_bar: foo hello 22 0x16 > BIT2|BIT3|0x10 > {0x1,0x2,0x646e6147,0x666c61,0x,0x,0x750aeffe,0x7} > ^^ > The array length is not right, should be {0x1,0x2}. > Gandalf (,)" > > This was caused by an update to have __print_array()'s second parameter > be the count of items in the array and not the size of the array. > > As there is already users of __print_array(), it can not change. But > the sample code can and we can also improve on the documentation about > __print_array() and __get_dynamic_array_len(). > > Link: > http://lkml.kernel.org/r/1436839171-31527-2-git-send-email-heku...@huawei.com > > Fixes: ac01ce1410fc2 ("tracing: Make ftrace_print_array_seq compute buf_len") > Reported-by: He Kuang > Signed-off-by: Steven Rostedt > --- > samples/trace_events/trace-events-sample.h | 7 +-- > 1 file changed, 5 insertions(+), 2 deletions(-) > > diff --git a/samples/trace_events/trace-events-sample.h > b/samples/trace_events/trace-events-sample.h > index 8965d1bb8811..125d6402f64f 100644 > --- a/samples/trace_events/trace-events-sample.h > +++ b/samples/trace_events/trace-events-sample.h > @@ -168,7 +168,10 @@ > * > * For __dynamic_array(int, foo, bar) use __get_dynamic_array(foo) > *Use __get_dynamic_array_len(foo) to get the length of the array > - *saved. > + *saved. Note, __get_dynamic_array_len() returns the total > allocated > + *length of the dynamic array; __print_array() expects the second > + *parameter to be the number of elements. To get that, the array > length > + *needs to be divided by the element size. > * > * For __string(foo, bar) use __get_str(foo) > * > @@ -288,7 +291,7 @@ TRACE_EVENT(foo_bar, > *This prints out the array that is defined by __array in a nice format. > */ > __print_array(__get_dynamic_array(list), > - __get_dynamic_array_len(list), > + __get_dynamic_array_len(list) / sizeof(int), > sizeof(int)), > __get_str(str), __get_bitmask(cpus)) > ); Reviewed-by: Alex Bennée -- Alex Bennée -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v8 02/11] KVM: arm64: guest debug, define API headers
This commit defines the API headers for guest debugging. There are two architecture specific debug structures: - kvm_guest_debug_arch, allows us to pass in HW debug registers - kvm_debug_exit_arch, signals exception and possible faulting address The type of debugging being used is controlled by the architecture specific control bits of the kvm_guest_debug->control flags in the ioctl structure. Signed-off-by: Alex Bennée Reviewed-by: David Hildenbrand Reviewed-by: Andrew Jones Acked-by: Christoffer Dall --- v2 - expose hsr and pc directly to user-space v3 - s/control/controlled/ in commit message - add v8 to ARM ARM comment (ARM Architecture Reference Manual) - add rb tag - rm pc, add far - re-word comments on alignment - rename KVM_ARM_NDBG_REGS -> KVM_ARM_MAX_DBG_REGS v4 - now uses common HW/SW BP define - add a-b-tag - use u32 for control regs v5 - revert to have arch specific KVM_GUESTDBG_USE_SW/HW_BP - rm stale comments dbgctrl was stored as u64 v6 - mv far comment from later patch - KVM_GUESTDBG_USE_HW_BP -> KVM_GUESTDBG_USE_HW - revert control regs to u64 (parity with GET/SET_ONE_REG) --- arch/arm64/include/uapi/asm/kvm.h | 27 +++ 1 file changed, 27 insertions(+) diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index d268320..d82f3f3 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -100,12 +100,39 @@ struct kvm_sregs { struct kvm_fpu { }; +/* + * See v8 ARM ARM D7.3: Debug Registers + * + * The architectural limit is 16 debug registers of each type although + * in practice there are usually less (see ID_AA64DFR0_EL1). + * + * Although the control registers are architecturally defined as 32 + * bits wide we use a 64 bit structure here to keep parity with + * KVM_GET/SET_ONE_REG behaviour which treats all system registers as + * 64 bit values. It also allows for the possibility of the + * architecture expanding the control registers without having to + * change the userspace ABI. + */ +#define KVM_ARM_MAX_DBG_REGS 16 struct kvm_guest_debug_arch { + __u64 dbg_bcr[KVM_ARM_MAX_DBG_REGS]; + __u64 dbg_bvr[KVM_ARM_MAX_DBG_REGS]; + __u64 dbg_wcr[KVM_ARM_MAX_DBG_REGS]; + __u64 dbg_wvr[KVM_ARM_MAX_DBG_REGS]; }; struct kvm_debug_exit_arch { + __u32 hsr; + __u64 far; /* used for watchpoints */ }; +/* + * Architecture specific defines for kvm_guest_debug->control + */ + +#define KVM_GUESTDBG_USE_SW_BP (1 << 16) +#define KVM_GUESTDBG_USE_HW(1 << 17) + struct kvm_sync_regs { }; -- 2.4.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v8 08/11] KVM: arm64: introduce vcpu->arch.debug_ptr
This introduces a level of indirection for the debug registers. Instead of using the sys_regs[] directly we store registers in a structure in the vcpu. The new kvm_arm_reset_debug_ptr() sets the debug ptr to the guest context. Because we no longer give the sys_regs offset for the sys_reg_desc->reg field, but instead the index into a debug-specific struct we need to add a number of additional trap functions for each register. Also as the generic generic user-space access code no longer works we have introduced a new pair of function pointers to the sys_reg_desc structure to override the generic code when needed. Signed-off-by: Alex Bennée --- v6: - fix up some ws issues - correct clobber info - re-word commentary in kvm_host.h - fix endian access issues for aarch32 fields - revert all KVM_GET/SET_ONE_REG to 64bit (also see ABI update) v7 - new fn kvm_arm_reset_debug_ptr(), stubbed for arm - split trap fns into bcr,bvr,bcr,wvr and wxvr - add set/get fns to sys_regs_desc - reg_to_dbg/dbg_to_reg helpers for 32bit support v8 - rm #if 0 left over from re-factor - re-word reset_ptr comment - fix inadvertent whitespace changes - rename get/set to get_user/set_user - update commit wording - re-factor dbg_to_reg/reg_to_dbg - add newlines to keep checkpatch happy - ensure 63:32 of debug registers untouched by aarch32 --- arch/arm/include/asm/kvm_host.h | 1 + arch/arm/kvm/arm.c| 2 + arch/arm64/include/asm/kvm_asm.h | 24 ++-- arch/arm64/include/asm/kvm_host.h | 17 ++- arch/arm64/kernel/asm-offsets.c | 6 + arch/arm64/kvm/debug.c| 9 ++ arch/arm64/kvm/hyp.S | 24 ++-- arch/arm64/kvm/sys_regs.c | 274 +++--- arch/arm64/kvm/sys_regs.h | 6 + 9 files changed, 316 insertions(+), 47 deletions(-) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 746c0c69..825c337 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -239,5 +239,6 @@ static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} static inline void kvm_arm_init_debug(void) {} static inline void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) {} static inline void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) {} +static inline void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu) {} #endif /* __ARM_KVM_HOST_H__ */ diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index af60e6f..525473f 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -279,6 +279,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) /* Set up the timer */ kvm_timer_vcpu_init(vcpu); + kvm_arm_reset_debug_ptr(vcpu); + return 0; } diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index d6b507e..e997404 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -46,24 +46,16 @@ #defineCNTKCTL_EL1 20 /* Timer Control Register (EL1) */ #definePAR_EL1 21 /* Physical Address Register */ #define MDSCR_EL1 22 /* Monitor Debug System Control Register */ -#define DBGBCR0_EL123 /* Debug Breakpoint Control Registers (0-15) */ -#define DBGBCR15_EL1 38 -#define DBGBVR0_EL139 /* Debug Breakpoint Value Registers (0-15) */ -#define DBGBVR15_EL1 54 -#define DBGWCR0_EL155 /* Debug Watchpoint Control Registers (0-15) */ -#define DBGWCR15_EL1 70 -#define DBGWVR0_EL171 /* Debug Watchpoint Value Registers (0-15) */ -#define DBGWVR15_EL1 86 -#define MDCCINT_EL187 /* Monitor Debug Comms Channel Interrupt Enable Reg */ +#define MDCCINT_EL123 /* Monitor Debug Comms Channel Interrupt Enable Reg */ /* 32bit specific registers. Keep them at the end of the range */ -#defineDACR32_EL2 88 /* Domain Access Control Register */ -#defineIFSR32_EL2 89 /* Instruction Fault Status Register */ -#defineFPEXC32_EL2 90 /* Floating-Point Exception Control Register */ -#defineDBGVCR32_EL291 /* Debug Vector Catch Register */ -#defineTEECR32_EL1 92 /* ThumbEE Configuration Register */ -#defineTEEHBR32_EL193 /* ThumbEE Handler Base Register */ -#defineNR_SYS_REGS 94 +#defineDACR32_EL2 24 /* Domain Access Control Register */ +#defineIFSR32_EL2 25 /* Instruction Fault Status Register */ +#defineFPEXC32_EL2 26 /* Floating-Point Exception Control Register */ +#defineDBGVCR32_EL227 /* Debug Vector Catch Register */ +#defineTEECR32_EL1 28 /* ThumbEE Configuration Register */ +#defineTEEHBR32_EL129 /* ThumbEE Handler Base Register */ +#defineNR_SYS_REGS 30 /* 32bit mapping */ #define c0_MPIDR (MPIDR_EL1 * 2) /* MultiProcessor ID Register */ diff --git a/arch/arm64/incl
[PATCH v8 05/11] KVM: arm64: guest debug, add SW break point support
This adds support for SW breakpoints inserted by userspace. We do this by trapping all guest software debug exceptions to the hypervisor (MDCR_EL2.TDE). The exit handler sets an exit reason of KVM_EXIT_DEBUG with the kvm_debug_exit_arch structure holding the exception syndrome information. It will be up to userspace to extract the PC (via GET_ONE_REG) and determine if the debug event was for a breakpoint it inserted. If not userspace will need to re-inject the correct exception restart the hypervisor to deliver the debug exception to the guest. Any other guest software debug exception (e.g. single step or HW assisted breakpoints) will cause an error and the VM to be killed. This is addressed by later patches which add support for the other debug types. Signed-off-by: Alex Bennée Reviewed-by: Christoffer Dall --- v2 - update to use new exit struct - tweak for C setup - do our setup in debug_setup/clear code - fixed up comments v3: - fix spacing in KVM_GUESTDBG_VALID_MASK - fix and clarify wording on kvm_handle_guest_debug - handle error case in kvm_handle_guest_debug - re-word the commit message v4 - rm else leg - add r-b-tag v7 - moved ioctl to guest --- Documentation/virtual/kvm/api.txt | 2 +- arch/arm64/kvm/debug.c| 3 +++ arch/arm64/kvm/guest.c| 2 +- arch/arm64/kvm/handle_exit.c | 36 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index ba635c7..33c8143 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2667,7 +2667,7 @@ when running. Common control bits are: The top 16 bits of the control field are architecture specific control flags which can include the following: - - KVM_GUESTDBG_USE_SW_BP: using software breakpoints [x86] + - KVM_GUESTDBG_USE_SW_BP: using software breakpoints [x86, arm64] - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390] - KVM_GUESTDBG_INJECT_DB: inject DB type exception [x86] - KVM_GUESTDBG_INJECT_BP: inject BP type exception [x86] diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index faf0e1f..8d1bfa4 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -73,6 +73,9 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) if (trap_debug) vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA; + /* Trap breakpoints? */ + if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) + vcpu->arch.mdcr_el2 |= MDCR_EL2_TDE; } void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 0ba8677..22d22c5 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -332,7 +332,7 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, return -EINVAL; } -#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE) +#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP) /** * kvm_arch_vcpu_ioctl_set_guest_debug - set up guest debugging diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 524fa25..27f38a9 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -82,6 +82,40 @@ static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run) return 1; } +/** + * kvm_handle_guest_debug - handle a debug exception instruction + * + * @vcpu: the vcpu pointer + * @run: access to the kvm_run structure for results + * + * We route all debug exceptions through the same handler. If both the + * guest and host are using the same debug facilities it will be up to + * userspace to re-inject the correct exception for guest delivery. + * + * @return: 0 (while setting run->exit_reason), -1 for error + */ +static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + u32 hsr = kvm_vcpu_get_hsr(vcpu); + int ret = 0; + + run->exit_reason = KVM_EXIT_DEBUG; + run->debug.arch.hsr = hsr; + + switch (hsr >> ESR_ELx_EC_SHIFT) { + case ESR_ELx_EC_BKPT32: + case ESR_ELx_EC_BRK64: + break; + default: + kvm_err("%s: un-handled case hsr: %#08x\n", + __func__, (unsigned int) hsr); + ret = -1; + break; + } + + return ret; +} + static exit_handle_fn arm_exit_handlers[] = { [ESR_ELx_EC_WFx]= kvm_handle_wfx, [ESR_ELx_EC_CP15_32]= kvm_handle_cp15_32, @@ -96,6 +130,8 @@ static exit_handle_fn arm_exit_handlers[] = { [ESR_ELx_EC_SYS64] = kvm_handle_sys_reg, [ESR_ELx_EC_IABT_LOW] = kvm_handle_guest_abort, [ESR_ELx_EC_DABT_LOW] = kvm_handle_guest_abort, + [ESR_ELx_EC_BKPT32] = kvm_handle_guest_debug, + [ESR_ELx_EC_BRK64] = kvm_handle_guest_debug, }; static exit
[PATCH v8 06/11] KVM: arm64: guest debug, add support for single-step
This adds support for single-stepping the guest. To do this we need to manipulate the guests PSTATE.SS and MDSCR_EL1.SS bits to trigger stepping. We take care to preserve MDSCR_EL1 and trap access to it to ensure we don't affect the apparent state of the guest. As we have to enable trapping of all software debug exceptions we suppress the ability of the guest to single-step itself. If we didn't we would have to deal with the exception arriving while the guest was in kernelspace when the guest is expecting to single-step userspace. This is something we don't want to unwind in the kernel. Once the host is no longer debugging the guest its ability to single-step userspace is restored. Signed-off-by: Alex Bennée Reviewed-by: Christoffer Dall --- v2 - Move pstate/mdscr manipulation into C - don't export guest_debug to assembly - add accessor for saved_debug regs - tweak save/restore of mdscr_el1 v3 - don't save PC in debug information struct - rename debug_saved_regs->guest_debug_state - save whole value, only use bits in restore - add save/restore_guest-debug_regs helper functions - simplify commit message for clarity - rm vcpu_debug_saved_reg access fn v4 - added more comments based on suggestions - guest_debug_state->guest_debug_preserved - no point masking restore, we will trap out v5 - more comments - don't bother preserving pstate.ss (guest never sees change) v6 - reword comments on guest SS suppression - simplify comment for save regs, SS explained in detail later on - add r-b-t (code) - expanded commit description v7 - merge fix for ioctl move to guest.c --- arch/arm64/include/asm/kvm_host.h | 11 +++ arch/arm64/kvm/debug.c| 68 --- arch/arm64/kvm/guest.c| 4 ++- arch/arm64/kvm/handle_exit.c | 2 ++ 4 files changed, 80 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 7cb99b5..e2db6a6 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -123,6 +123,17 @@ struct kvm_vcpu_arch { * here. */ + /* +* Guest registers we preserve during guest debugging. +* +* These shadow registers are updated by the kvm_handle_sys_reg +* trap handler if the guest accesses or updates them while we +* are using guest debug. +*/ + struct { + u32 mdscr_el1; + } guest_debug_preserved; + /* Don't run the guest */ bool pause; diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index 8d1bfa4..d439eb8 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -19,11 +19,39 @@ #include +#include +#include #include +#include + +/* These are the bits of MDSCR_EL1 we may manipulate */ +#define MDSCR_EL1_DEBUG_MASK (DBG_MDSCR_SS | \ + DBG_MDSCR_KDE | \ + DBG_MDSCR_MDE) static DEFINE_PER_CPU(u32, mdcr_el2); /** + * save/restore_guest_debug_regs + * + * For some debug operations we need to tweak some guest registers. As + * a result we need to save the state of those registers before we + * make those modifications. + * + * Guest access to MDSCR_EL1 is trapped by the hypervisor and handled + * after we have restored the preserved value to the main context. + */ +static void save_guest_debug_regs(struct kvm_vcpu *vcpu) +{ + vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1); +} + +static void restore_guest_debug_regs(struct kvm_vcpu *vcpu) +{ + vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1; +} + +/** * kvm_arm_init_debug - grab what we need for debug * * Currently the sole task of this function is to retrieve the initial @@ -38,7 +66,6 @@ void kvm_arm_init_debug(void) __this_cpu_write(mdcr_el2, kvm_call_hyp(__kvm_get_mdcr_el2)); } - /** * kvm_arm_setup_debug - set up debug related stuff * @@ -73,12 +100,45 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) if (trap_debug) vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA; - /* Trap breakpoints? */ - if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) + /* Is Guest debugging in effect? */ + if (vcpu->guest_debug) { + /* Route all software debug exceptions to EL2 */ vcpu->arch.mdcr_el2 |= MDCR_EL2_TDE; + + /* Save guest debug state */ + save_guest_debug_regs(vcpu); + + /* +* Single Step (ARM ARM D2.12.3 The software step state +* machine) +* +* If we are doing Single Step we need to manipulate +* the guest's MDSCR_EL1.SS and PSTATE.SS. Once the +* step has occurred the hypervisor will tr
[PATCH v8 11/11] KVM: arm64: add trace points for guest_debug debug
This includes trace points for: kvm_arch_setup_guest_debug kvm_arch_clear_guest_debug I've also added some generic register setting trace events and also a trace point to dump the array of hardware registers. Signed-off-by: Alex Bennée --- v3 - add trace event for debug access. - remove short trace #define, rename trace events - use __print_array with fixed array instead of own func - rationalise trace points (only one per register changed) - add vcpu ptr to the debug_setup trace - remove :: in prints v4 - u32/u64 split on debug registers - fix for renames - add tracing of traps/set_guest_debug - remove handle_guest_debug trace v5 - minor print fmt fix - rm pstate traces v6 - fix merge conflicts - update control reg tracking to u64 (abi change) v7 - fix merge conflicts from ioctl move - fix other minor merge conflicts - fixes for the re-factored sys_regs code v8 - updates for sys_regs re-factor --- arch/arm64/kvm/debug.c| 36 +- arch/arm64/kvm/guest.c| 4 ++ arch/arm64/kvm/sys_regs.c | 17 +++ arch/arm64/kvm/trace.h| 123 ++ 4 files changed, 179 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index 4a99e54..47e5f0f 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -18,12 +18,15 @@ */ #include +#include #include #include #include #include +#include "trace.h" + /* These are the bits of MDSCR_EL1 we may manipulate */ #define MDSCR_EL1_DEBUG_MASK (DBG_MDSCR_SS | \ DBG_MDSCR_KDE | \ @@ -44,11 +47,17 @@ static DEFINE_PER_CPU(u32, mdcr_el2); static void save_guest_debug_regs(struct kvm_vcpu *vcpu) { vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1); + + trace_kvm_arm_set_dreg32("Saved MDSCR_EL1", + vcpu->arch.guest_debug_preserved.mdscr_el1); } static void restore_guest_debug_regs(struct kvm_vcpu *vcpu) { vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1; + + trace_kvm_arm_set_dreg32("Restored MDSCR_EL1", + vcpu_sys_reg(vcpu, MDSCR_EL1)); } /** @@ -99,6 +108,8 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) { bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY); + trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug); + vcpu->arch.mdcr_el2 = __this_cpu_read(mdcr_el2) & MDCR_EL2_HPMN_MASK; vcpu->arch.mdcr_el2 |= (MDCR_EL2_TPM | MDCR_EL2_TPMCR | @@ -140,6 +151,8 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) vcpu_sys_reg(vcpu, MDSCR_EL1) &= ~DBG_MDSCR_SS; } + trace_kvm_arm_set_dreg32("SPSR_EL2", *vcpu_cpsr(vcpu)); + /* * HW Breakpoints and watchpoints * @@ -156,6 +169,14 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) vcpu->arch.debug_ptr = &vcpu->arch.external_debug_state; vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; trap_debug = true; + + trace_kvm_arm_set_regset("BKPTS", get_num_brps(), + &vcpu->arch.debug_ptr->dbg_bcr[0], + &vcpu->arch.debug_ptr->dbg_bvr[0]); + + trace_kvm_arm_set_regset("WAPTS", get_num_wrps(), + &vcpu->arch.debug_ptr->dbg_wcr[0], + &vcpu->arch.debug_ptr->dbg_wvr[0]); } } @@ -165,10 +186,15 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) /* Trap debug register access */ if (trap_debug) vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA; + + trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2); + trace_kvm_arm_set_dreg32("MDSCR_EL1", vcpu_sys_reg(vcpu, MDSCR_EL1)); } void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) { + trace_kvm_arm_clear_debug(vcpu->guest_debug); + if (vcpu->guest_debug) { restore_guest_debug_regs(vcpu); @@ -176,8 +202,16 @@ void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) * If we were using HW debug we need to restore the * debug_ptr to the guest debug state. */ - if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) + if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) { kvm_arm_reset_debug_ptr(vcpu); + trace_kvm_arm_set_regset("BKPTS", get_num_brps(), +
[PATCH v8 10/11] KVM: arm64: enable KVM_CAP_SET_GUEST_DEBUG
Finally advertise the KVM capability for SET_GUEST_DEBUG. Once arm support is added this check can be moved to the common kvm_vm_ioctl_check_extension() code. Signed-off-by: Alex Bennée Acked-by: Christoffer Dall --- v3: - separated capability check from previous patches - moved into arm64 specific ioctl handler. v4: - add a-b-tag --- arch/arm64/kvm/reset.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index 8620926..b4af618 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -77,6 +77,9 @@ int kvm_arch_dev_ioctl_check_extension(long ext) case KVM_CAP_GUEST_DEBUG_HW_WPS: r = get_num_wrps(); break; + case KVM_CAP_SET_GUEST_DEBUG: + r = 1; + break; default: r = 0; } -- 2.4.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v8 07/11] KVM: arm64: re-factor hyp.S debug register code
This is a pre-cursor to sharing the code with the guest debug support. This replaces the big macro that fishes data out of a fixed location with a more general helper macro to restore a set of debug registers. It uses macro substitution so it can be re-used for debug control and value registers. It does however rely on the debug registers being 64 bit aligned (as they happen to be in the hyp ABI). Signed-off-by: Alex Bennée Reviewed-by: Christoffer Dall --- v3: - return to the patch series - add save and restore targets - change register use and document v4: - keep original setup/restore names - don't use split u32/u64 structure yet v6: - fix ws and clobber info in hyp.S v7: - fix whitespace - add r-b-tag --- arch/arm64/kvm/hyp.S | 517 ++- 1 file changed, 138 insertions(+), 379 deletions(-) diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S index 2c67a14..77c08df 100644 --- a/arch/arm64/kvm/hyp.S +++ b/arch/arm64/kvm/hyp.S @@ -228,199 +228,52 @@ stp x24, x25, [x3, #160] .endm -.macro save_debug - // x2: base address for cpu context - // x3: tmp register - - mrs x26, id_aa64dfr0_el1 - ubfxx24, x26, #12, #4 // Extract BRPs - ubfxx25, x26, #20, #4 // Extract WRPs - mov w26, #15 - sub w24, w26, w24 // How many BPs to skip - sub w25, w26, w25 // How many WPs to skip - - add x3, x2, #CPU_SYSREG_OFFSET(DBGBCR0_EL1) - - adr x26, 1f - add x26, x26, x24, lsl #2 - br x26 -1: - mrs x20, dbgbcr15_el1 - mrs x19, dbgbcr14_el1 - mrs x18, dbgbcr13_el1 - mrs x17, dbgbcr12_el1 - mrs x16, dbgbcr11_el1 - mrs x15, dbgbcr10_el1 - mrs x14, dbgbcr9_el1 - mrs x13, dbgbcr8_el1 - mrs x12, dbgbcr7_el1 - mrs x11, dbgbcr6_el1 - mrs x10, dbgbcr5_el1 - mrs x9, dbgbcr4_el1 - mrs x8, dbgbcr3_el1 - mrs x7, dbgbcr2_el1 - mrs x6, dbgbcr1_el1 - mrs x5, dbgbcr0_el1 - - adr x26, 1f - add x26, x26, x24, lsl #2 - br x26 - -1: - str x20, [x3, #(15 * 8)] - str x19, [x3, #(14 * 8)] - str x18, [x3, #(13 * 8)] - str x17, [x3, #(12 * 8)] - str x16, [x3, #(11 * 8)] - str x15, [x3, #(10 * 8)] - str x14, [x3, #(9 * 8)] - str x13, [x3, #(8 * 8)] - str x12, [x3, #(7 * 8)] - str x11, [x3, #(6 * 8)] - str x10, [x3, #(5 * 8)] - str x9, [x3, #(4 * 8)] - str x8, [x3, #(3 * 8)] - str x7, [x3, #(2 * 8)] - str x6, [x3, #(1 * 8)] - str x5, [x3, #(0 * 8)] - - add x3, x2, #CPU_SYSREG_OFFSET(DBGBVR0_EL1) - - adr x26, 1f - add x26, x26, x24, lsl #2 - br x26 -1: - mrs x20, dbgbvr15_el1 - mrs x19, dbgbvr14_el1 - mrs x18, dbgbvr13_el1 - mrs x17, dbgbvr12_el1 - mrs x16, dbgbvr11_el1 - mrs x15, dbgbvr10_el1 - mrs x14, dbgbvr9_el1 - mrs x13, dbgbvr8_el1 - mrs x12, dbgbvr7_el1 - mrs x11, dbgbvr6_el1 - mrs x10, dbgbvr5_el1 - mrs x9, dbgbvr4_el1 - mrs x8, dbgbvr3_el1 - mrs x7, dbgbvr2_el1 - mrs x6, dbgbvr1_el1 - mrs x5, dbgbvr0_el1 - - adr x26, 1f - add x26, x26, x24, lsl #2 - br x26 - -1: - str x20, [x3, #(15 * 8)] - str x19, [x3, #(14 * 8)] - str x18, [x3, #(13 * 8)] - str x17, [x3, #(12 * 8)] - str x16, [x3, #(11 * 8)] - str x15, [x3, #(10 * 8)] - str x14, [x3, #(9 * 8)] - str x13, [x3, #(8 * 8)] - str x12, [x3, #(7 * 8)] - str x11, [x3, #(6 * 8)] - str x10, [x3, #(5 * 8)] - str x9, [x3, #(4 * 8)] - str x8, [x3, #(3 * 8)] - str x7, [x3, #(2 * 8)] - str x6, [x3, #(1 * 8)] - str x5, [x3, #(0 * 8)] - - add x3, x2, #CPU_SYSREG_OFFSET(DBGWCR0_EL1) - - adr x26, 1f - add x26, x26, x25, lsl #2 - br x26 +.macro save_debug type + // x4: pointer to register set + // x5: number of registers to skip + // x6..x22 trashed + + adr x22, 1f + add x22, x22, x5, lsl #2 + br x22 1: - mrs x20, dbgwcr15_el1 - mrs x19, dbgwcr14_el1 - mrs x18, dbgwcr13_el1 - mrs x17, dbgwcr12_el1 - mrs x16, dbgwcr11_el1 - mrs x15, dbgwcr10_el1 - mrs x14, dbgwcr9_el1 - mrs x13, dbgwcr8_el1 - mrs x12, dbgwcr7_el1 - mrs x11, dbgwcr6_el1 - mrs x10, dbgwcr5_el1 - mrs x9, dbgwcr4_el1 - mrs x8, dbgwcr3_el1 - mrs x7, dbgwcr
[PATCH v8 01/11] KVM: add comments for kvm_debug_exit_arch struct
Bring into line with the comments for the other structures and their KVM_EXIT_* cases. Also update api.txt to reflect use in kvm_run documentation. Signed-off-by: Alex Bennée Reviewed-by: David Hildenbrand Reviewed-by: Andrew Jones Acked-by: Christoffer Dall --- v2 - add comments for other exit types v3 - s/commentary/comments/ - add rb tags - update api.txt kvm_run to include KVM_EXIT_DEBUG desc v4 - sp fixes - add a-b --- Documentation/virtual/kvm/api.txt | 4 +++- include/uapi/linux/kvm.h | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 9fa2bf8..c34c32d 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -3070,11 +3070,13 @@ data_offset describes where the data is located (KVM_EXIT_IO_OUT) or where kvm expects application code to place the data for the next KVM_RUN invocation (KVM_EXIT_IO_IN). Data format is a packed array. + /* KVM_EXIT_DEBUG */ struct { struct kvm_debug_exit_arch arch; } debug; -Unused. +If the exit_reason is KVM_EXIT_DEBUG, then a vcpu is processing a debug event +for which architecture specific information is returned. /* KVM_EXIT_MMIO */ struct { diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 4b60056..70ac641 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -237,6 +237,7 @@ struct kvm_run { __u32 count; __u64 data_offset; /* relative to kvm_run start */ } io; + /* KVM_EXIT_DEBUG */ struct { struct kvm_debug_exit_arch arch; } debug; @@ -285,6 +286,7 @@ struct kvm_run { __u32 data; __u8 is_write; } dcr; + /* KVM_EXIT_INTERNAL_ERROR */ struct { __u32 suberror; /* Available with KVM_CAP_INTERNAL_ERROR_DATA: */ @@ -295,6 +297,7 @@ struct kvm_run { struct { __u64 gprs[32]; } osi; + /* KVM_EXIT_PAPR_HCALL */ struct { __u64 nr; __u64 ret; -- 2.4.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v8 09/11] KVM: arm64: guest debug, HW assisted debug support
This adds support for userspace to control the HW debug registers for guest debug. In the debug ioctl we copy an IMPDEF registers into a new register set called host_debug_state. We use the recently introduced vcpu parameter debug_ptr to select which register set is copied into the real registers when world switch occurs. I've made some helper functions from hw_breakpoint.c more widely available for re-use. As with single step we need to tweak the guest registers to enable the exceptions so we need to save and restore those bits. Two new capabilities have been added to the KVM_EXTENSION ioctl to allow userspace to query the number of hardware break and watch points available on the host hardware. Signed-off-by: Alex Bennée Reviewed-by: Christoffer Dall --- v2 - switched to C setup - replace host debug registers directly into context - minor tweak to api docs - setup right register for debug - add FAR_EL2 to debug exit structure - add support for trapping debug register access v3 - remove stray trace statement - fix spacing around operators (various) - clean-up usage of trap_debug - introduce debug_ptr, replace excessive memcpy stuff - don't use memcpy in ioctl, just assign - update cap ioctl documentation - reword a number comments - rename host_debug_state->external_debug_state v4 - use the new u32/u64 split debug_ptr approach - fix some wording/comments v5 - don't set MDSCR_EL1.KDE (not needed) v6 - update wording given change in commentary - KVM_GUESTDBG_USE_HW_BP->KVM_GUESTDBG_USE_HW v7 - fix merge conflicts from ioctl move to guest.c - use kvm_arm_reset_debug_ptr to reset ptr - a BUG_ON() test has been added to trap failure to reset debug_ptr - debugging->debug in kvm_host.h comment - s/defined// s/to// in commit msg - rm ref to introducing debug_ptr in commit msg - add r-b tag v8 - add #include to hw_breakpoint.h --- Documentation/virtual/kvm/api.txt | 7 +- arch/arm64/include/asm/hw_breakpoint.h | 14 arch/arm64/include/asm/kvm_host.h | 6 - arch/arm64/kernel/hw_breakpoint.c | 12 -- arch/arm64/kvm/debug.c | 40 +- arch/arm64/kvm/guest.c | 7 ++ arch/arm64/kvm/handle_exit.c | 6 + arch/arm64/kvm/reset.c | 13 +++ include/uapi/linux/kvm.h | 2 ++ 9 files changed, 88 insertions(+), 19 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 33c8143..ada57df 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2668,7 +2668,7 @@ The top 16 bits of the control field are architecture specific control flags which can include the following: - KVM_GUESTDBG_USE_SW_BP: using software breakpoints [x86, arm64] - - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390] + - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390, arm64] - KVM_GUESTDBG_INJECT_DB: inject DB type exception [x86] - KVM_GUESTDBG_INJECT_BP: inject BP type exception [x86] - KVM_GUESTDBG_EXIT_PENDING: trigger an immediate guest exit [s390] @@ -2683,6 +2683,11 @@ updated to the correct (supplied) values. The second part of the structure is architecture specific and typically contains a set of debug registers. +For arm64 the number of debug registers is implementation defined and +can be determined by querying the KVM_CAP_GUEST_DEBUG_HW_BPS and +KVM_CAP_GUEST_DEBUG_HW_WPS capabilities which return a positive number +indicating the number of supported registers. + When debug events exit the main run loop with the reason KVM_EXIT_DEBUG with the kvm_debug_exit_arch part of the kvm_run structure containing architecture specific debug information. diff --git a/arch/arm64/include/asm/hw_breakpoint.h b/arch/arm64/include/asm/hw_breakpoint.h index 52b484b..4c47cb2 100644 --- a/arch/arm64/include/asm/hw_breakpoint.h +++ b/arch/arm64/include/asm/hw_breakpoint.h @@ -16,6 +16,8 @@ #ifndef __ASM_HW_BREAKPOINT_H #define __ASM_HW_BREAKPOINT_H +#include + #ifdef __KERNEL__ struct arch_hw_breakpoint_ctrl { @@ -132,5 +134,17 @@ static inline void ptrace_hw_copy_thread(struct task_struct *task) extern struct pmu perf_ops_bp; +/* Determine number of BRP registers available. */ +static inline int get_num_brps(void) +{ + return ((read_cpuid(ID_AA64DFR0_EL1) >> 12) & 0xf) + 1; +} + +/* Determine number of WRP registers available. */ +static inline int get_num_wrps(void) +{ + return ((read_cpuid(ID_AA64DFR0_EL1) >> 20) & 0xf) + 1; +} + #endif /* __KERNEL__ */ #endif /* __ASM_BREAKPOINT_H */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 461d288..6c745e0 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.
[PATCH v8 04/11] KVM: arm: introduce kvm_arm_init/setup/clear_debug
This is a precursor for later patches which will need to do more to setup debug state before entering the hyp.S switch code. The existing functionality for setting mdcr_el2 has been moved out of hyp.S and now uses the value kept in vcpu->arch.mdcr_el2. As the assembler used to previously mask and preserve MDCR_EL2.HPMN I've had to add a mechanism to save the value of mdcr_el2 as a per-cpu variable during the initialisation code. The kernel never sets this number so we are assuming the bootcode has set up the correct value here. This also moves the conditional setting of the TDA bit from the hyp code into the C code which is currently used for the lazy debug register context switch code. Signed-off-by: Alex Bennée Reviewed-by: Christoffer Dall --- v3 - rename fns from arch->arm - preserve MDCR_EL2.HPMN setting - re-word some of the comments - fix some minor grammar nits - merge setting of mdcr_el2 - introduce trap_debug flag - move setup/clear within the irq lock section v4 - fix TDOSA desc - rm un-needed else leg - s/arch/arm/ v6 - add s-o-b tag --- arch/arm/include/asm/kvm_host.h | 4 ++ arch/arm/kvm/arm.c| 9 - arch/arm64/include/asm/kvm_asm.h | 2 + arch/arm64/include/asm/kvm_host.h | 5 +++ arch/arm64/kernel/asm-offsets.c | 1 + arch/arm64/kvm/Makefile | 2 +- arch/arm64/kvm/debug.c| 81 +++ arch/arm64/kvm/hyp.S | 19 - 8 files changed, 110 insertions(+), 13 deletions(-) create mode 100644 arch/arm64/kvm/debug.c diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index d71607c..746c0c69 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -236,4 +236,8 @@ 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) {} +static inline void kvm_arm_init_debug(void) {} +static inline void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) {} +static inline void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) {} + #endif /* __ARM_KVM_HOST_H__ */ diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 92b80bc..af60e6f 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -542,6 +542,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) continue; } + kvm_arm_setup_debug(vcpu); + /** * Enter the guest */ @@ -554,7 +556,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) vcpu->mode = OUTSIDE_GUEST_MODE; kvm_guest_exit(); trace_kvm_exit(kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu)); - /* + + kvm_arm_clear_debug(vcpu); + +/* * We may have taken a host interrupt in HYP mode (ie * while executing the guest). This interrupt is still * pending, as we haven't serviced it yet! @@ -902,6 +907,8 @@ static void cpu_init_hyp_mode(void *dummy) vector_ptr = (unsigned long)__kvm_hyp_vector; __cpu_init_hyp_mode(boot_pgd_ptr, pgd_ptr, hyp_stack_ptr, vector_ptr); + + kvm_arm_init_debug(); } static int hyp_init_cpu_notify(struct notifier_block *self, diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index 4f7310f..d6b507e 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -137,6 +137,8 @@ extern char __restore_vgic_v2_state[]; extern char __save_vgic_v3_state[]; extern char __restore_vgic_v3_state[]; +extern u32 __kvm_get_mdcr_el2(void); + #endif #endif /* __ARM_KVM_ASM_H__ */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index f0f58c9..7cb99b5 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -103,6 +103,7 @@ struct kvm_vcpu_arch { /* HYP configuration */ u64 hcr_el2; + u32 mdcr_el2; /* Exception Information */ struct kvm_vcpu_fault_info fault; @@ -250,4 +251,8 @@ 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) {} +void kvm_arm_init_debug(void); +void kvm_arm_setup_debug(struct kvm_vcpu *vcpu); +void kvm_arm_clear_debug(struct kvm_vcpu *vcpu); + #endif /* __ARM64_KVM_HOST_H__ */ diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index da675cc..dfb25a2 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -117,6 +117,7 @@ int main(void) DEFINE(VCPU_HPFAR_EL2, offsetof(struct kvm_vcpu, a
[PATCH v8 03/11] KVM: arm: guest debug, add stub KVM_SET_GUEST_DEBUG ioctl
This commit adds a stub function to support the KVM_SET_GUEST_DEBUG ioctl. Any unsupported flag will return -EINVAL. For now, only KVM_GUESTDBG_ENABLE is supported, although it won't have any effects. Signed-off-by: Alex Bennée . Reviewed-by: Christoffer Dall --- v2 - simplified form of the ioctl (stuff will go into setup_debug) v3 - KVM_GUESTDBG_VALID->KVM_GUESTDBG_VALID_MASK - move mask check to the top of function - add ioctl doc header - split capability into separate patch - tweaked commit wording w.r.t return of -EINVAL v4 - add r-b-tag v7 - moved ioctl to arm64/kvm/guest.c, stubbed arm/kvm/guest.c --- Documentation/virtual/kvm/api.txt | 2 +- arch/arm/kvm/arm.c| 7 --- arch/arm/kvm/guest.c | 6 ++ arch/arm64/kvm/guest.c| 27 +++ 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index c34c32d..ba635c7 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2645,7 +2645,7 @@ handled. 4.87 KVM_SET_GUEST_DEBUG Capability: KVM_CAP_SET_GUEST_DEBUG -Architectures: x86, s390, ppc +Architectures: x86, s390, ppc, arm64 Type: vcpu ioctl Parameters: struct kvm_guest_debug (in) Returns: 0 on success; -1 on error diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index d9631ec..92b80bc 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -302,13 +302,6 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) kvm_arm_set_running_vcpu(NULL); } -int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, - struct kvm_guest_debug *dbg) -{ - return -EINVAL; -} - - int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, struct kvm_mp_state *mp_state) { diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c index d503fbb..96e935b 100644 --- a/arch/arm/kvm/guest.c +++ b/arch/arm/kvm/guest.c @@ -290,3 +290,9 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, { return -EINVAL; } + +int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, + struct kvm_guest_debug *dbg) +{ + return -EINVAL; +} diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 9535bd5..0ba8677 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -331,3 +331,30 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, { return -EINVAL; } + +#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE) + +/** + * kvm_arch_vcpu_ioctl_set_guest_debug - set up guest debugging + * @kvm: pointer to the KVM struct + * @kvm_guest_debug: the ioctl data buffer + * + * This sets up and enables the VM for guest debugging. Userspace + * passes in a control flag to enable different debug types and + * potentially other architecture specific information in the rest of + * the structure. + */ +int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, + struct kvm_guest_debug *dbg) +{ + if (dbg->control & ~KVM_GUESTDBG_VALID_MASK) + return -EINVAL; + + if (dbg->control & KVM_GUESTDBG_ENABLE) { + vcpu->guest_debug = dbg->control; + } else { + /* If not enabled clear all flags */ + vcpu->guest_debug = 0; + } + return 0; +} -- 2.4.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v7 09/11] KVM: arm64: guest debug, HW assisted debug support
Will Deacon writes: > On Fri, Jul 03, 2015 at 05:07:41PM +0100, Alex Bennée wrote: >> Will Deacon writes: >> > On Thu, Jul 02, 2015 at 02:50:33PM +0100, Alex Bennée wrote: >> >> Are you happy with this?: >> > >> > [...] >> > >> >> +/** >> >> + * kvm_arch_dev_ioctl_check_extension >> >> + * >> >> + * We currently assume that the number of HW registers is uniform >> >> + * across all CPUs (see cpuinfo_sanity_check). >> >> + */ >> >> int kvm_arch_dev_ioctl_check_extension(long ext) >> >> { >> >> int r; >> >> @@ -64,6 +71,12 @@ int kvm_arch_dev_ioctl_check_extension(long ext) >> >> case KVM_CAP_ARM_EL1_32BIT: >> >> r = cpu_has_32bit_el1(); >> >> break; >> >> + case KVM_CAP_GUEST_DEBUG_HW_BPS: >> >> + r = hw_breakpoint_slots(TYPE_INST); >> >> + break; >> >> + case KVM_CAP_GUEST_DEBUG_HW_WPS: >> >> + r = hw_breakpoint_slots(TYPE_DATA); >> >> + break; >> > >> > Whilst I much prefer this code, it actually adds an unwanted dependency >> > on PERF_EVENTS that I didn't think about to start with. Sorry to keep >> > messing you about -- I guess your original patch is the best thing after >> > all. >> >> Everything looks to be in hw_breakpoint.[ch] which does depend on >> CONFIG_HAVE_HW_BREAKPOINT which depends on PERF_EVENTS to be built. >> However the previous code depended on this behaviour as well. > > I think your original approach (of sticking stuff in the header file) works > regardless of the CONFIG option, no? Ahh yeah I reverted that to an extern due to random compile breakage: http://storage.kernelci.org/alex/v4.1-12-gd38574dba3ec/arm64-allmodconfig/build.log I'll see if I can fix that up. >> It would seem weird to enable guest debug using HW debug registers to >> debug the guest yet not allowing the host kernel to use them? Of course >> this is the only code they would share as all the magic of guest >> debugging is already mostly there for dirty guest handling. >> >> I'm not familiar with Kconfig but it looks like this is all part of >> arm64 defconfig. Are people really going to want to disable PERF_EVENTS >> but still debug their guests with HW support? > > Then it's your call. I just find the host dependency on perf a bit weird > to get guest debug working (especially as the dependency is completely > "fake" because we don't use any perf infrastructure at all). > > Will -- Alex Bennée -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v7 09/11] KVM: arm64: guest debug, HW assisted debug support
Will Deacon writes: > Hi Alex, > > On Thu, Jul 02, 2015 at 02:50:33PM +0100, Alex Bennée wrote: >> Are you happy with this?: > > [...] > >> +/** >> + * kvm_arch_dev_ioctl_check_extension >> + * >> + * We currently assume that the number of HW registers is uniform >> + * across all CPUs (see cpuinfo_sanity_check). >> + */ >> int kvm_arch_dev_ioctl_check_extension(long ext) >> { >> int r; >> @@ -64,6 +71,12 @@ int kvm_arch_dev_ioctl_check_extension(long ext) >> case KVM_CAP_ARM_EL1_32BIT: >> r = cpu_has_32bit_el1(); >> break; >> + case KVM_CAP_GUEST_DEBUG_HW_BPS: >> + r = hw_breakpoint_slots(TYPE_INST); >> + break; >> + case KVM_CAP_GUEST_DEBUG_HW_WPS: >> + r = hw_breakpoint_slots(TYPE_DATA); >> + break; > > Whilst I much prefer this code, it actually adds an unwanted dependency > on PERF_EVENTS that I didn't think about to start with. Sorry to keep > messing you about -- I guess your original patch is the best thing after > all. Everything looks to be in hw_breakpoint.[ch] which does depend on CONFIG_HAVE_HW_BREAKPOINT which depends on PERF_EVENTS to be built. However the previous code depended on this behaviour as well. It would seem weird to enable guest debug using HW debug registers to debug the guest yet not allowing the host kernel to use them? Of course this is the only code they would share as all the magic of guest debugging is already mostly there for dirty guest handling. I'm not familiar with Kconfig but it looks like this is all part of arm64 defconfig. Are people really going to want to disable PERF_EVENTS but still debug their guests with HW support? > > Will -- Alex Bennée -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v7 08/11] KVM: arm64: introduce vcpu->arch.debug_ptr
Christoffer Dall writes: > On Wed, Jul 01, 2015 at 07:29:00PM +0100, Alex Bennée wrote: >> This introduces a level of indirection for the debug registers. Instead >> of using the sys_regs[] directly we store registers in a structure in >> the vcpu. The new kvm_arm_reset_debug_ptr() sets the debug ptr to the >> guest context. >> >> This also entails updating the sys_regs code to access this new >> structure. New access function have been added for each set of debug >> registers. The generic functions are still used for the few registers >> stored in the main context. >> >> New access function pointers have been added to the sys_reg_desc >> structure to support the GET/SET_ONE_REG ioctl operations. > > Why is this needed? Previously I had a hacky: if (r->access == trap_debug64) return debug_get64(vcpu, r, reg, uaddr); Which used the same offset information. Now we have a cleaner: if (r->set) return (r->set)(vcpu, r, reg, uaddr); Which accesses the structure directly, as the trap functions do: __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg]; if (copy_from_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0) return -EFAULT; return 0; >> +#if 0 >> +static int debug_set64(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, >> +const struct kvm_one_reg *reg, void __user *uaddr) >> +{ >> +__u64 *r = (__u64 *) ((void * )&vcpu->arch.vcpu_debug_state + rd->reg); >> +if (copy_from_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0) >> +return -EFAULT; >> +return 0; >> +} >> + >> +static int debug_get64(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, >> +const struct kvm_one_reg *reg, void __user *uaddr) >> +{ >> +__u64 *r = (__u64 *) ((void * )&vcpu->arch.vcpu_debug_state + rd->reg); >> +if (copy_to_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0) >> +return -EFAULT; >> +return 0; >> +} >> +#endif >> + > > what is this ifdef'ed block of code doing here? Oops. Yeah looks like I missed removing that after I finished the re-factor. These where the old get/set functions I used. > >> int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg >> *reg) >> { >> const struct sys_reg_desc *r; >> @@ -1303,6 +1530,9 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, >> const struct kvm_one_reg *reg >> if (!r) >> return get_invariant_sys_reg(reg->id, uaddr); >> >> +if (r->get) >> +return (r->get)(vcpu, r, reg, uaddr); >> + >> return reg_to_user(uaddr, &vcpu_sys_reg(vcpu, r->reg), reg->id); >> } >> >> @@ -1321,6 +1551,9 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, >> const struct kvm_one_reg *reg >> if (!r) >> return set_invariant_sys_reg(reg->id, uaddr); >> >> +if (r->set) >> +return (r->set)(vcpu, r, reg, uaddr); >> + >> return reg_from_user(&vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id); >> } >> >> diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h >> index d411e25..9265e7d 100644 >> --- a/arch/arm64/kvm/sys_regs.h >> +++ b/arch/arm64/kvm/sys_regs.h >> @@ -55,6 +55,12 @@ struct sys_reg_desc { >> >> /* Value (usually reset value) */ >> u64 val; >> + >> +/* Get/Set functions, fallback if NULL */ > > Is this only meant for usersapce access or when should one use these? Yes for GET/SET > >> +int (*get)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, void __user *uaddr); >> +int (*set)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, void __user *uaddr); >> }; >> >> static inline void print_sys_reg_instr(const struct sys_reg_params *p) >> -- >> 2.4.5 >> -- Alex Bennée -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v7 09/11] KVM: arm64: guest debug, HW assisted debug support
Will Deacon writes: Are you happy with this?: Subject: [PATCH v8 09/11] KVM: arm64: guest debug, HW assisted debug support This adds support for userspace to control the HW debug registers for guest debug. In the debug ioctl we copy an IMPDEF registers into a new register set called host_debug_state. We use the recently introduced vcpu parameter debug_ptr to select which register set is copied into the real registers when world switch occurs. I've made some helper functions from hw_breakpoint.c more widely available for re-use. As with single step we need to tweak the guest registers to enable the exceptions so we need to save and restore those bits. Two new capabilities have been added to the KVM_EXTENSION ioctl to allow userspace to query the number of hardware break and watch points available on the host hardware. Signed-off-by: Alex Bennée Reviewed-by: Christoffer Dall --- v2 - switched to C setup - replace host debug registers directly into context - minor tweak to api docs - setup right register for debug - add FAR_EL2 to debug exit structure - add support for trapping debug register access v3 - remove stray trace statement - fix spacing around operators (various) - clean-up usage of trap_debug - introduce debug_ptr, replace excessive memcpy stuff - don't use memcpy in ioctl, just assign - update cap ioctl documentation - reword a number comments - rename host_debug_state->external_debug_state v4 - use the new u32/u64 split debug_ptr approach - fix some wording/comments v5 - don't set MDSCR_EL1.KDE (not needed) v6 - update wording given change in commentary - KVM_GUESTDBG_USE_HW_BP->KVM_GUESTDBG_USE_HW v7 - fix merge conflicts from ioctl move to guest.c - use kvm_arm_reset_debug_ptr to reset ptr - a BUG_ON() test has been added to trap failure to reset debug_ptr - debugging->debug in kvm_host.h comment - s/defined// s/to// in commit msg - rm ref to introducing debug_ptr in commit msg - add r-b tag v8 - use hw_breakpoint_slots() instead --- Documentation/virtual/kvm/api.txt | 7 ++- arch/arm64/include/asm/kvm_host.h | 6 +- arch/arm64/kvm/debug.c| 40 ++- arch/arm64/kvm/guest.c| 7 +++ arch/arm64/kvm/handle_exit.c | 6 ++ arch/arm64/kvm/reset.c| 13 + arch/arm64/kvm/sys_regs.c | 3 --- include/uapi/linux/kvm.h | 2 ++ 8 files changed, 74 insertions(+), 10 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 33c8143..ada57df 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2668,7 +2668,7 @@ The top 16 bits of the control field are architecture specific control flags which can include the following: - KVM_GUESTDBG_USE_SW_BP: using software breakpoints [x86, arm64] - - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390] + - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390, arm64] - KVM_GUESTDBG_INJECT_DB: inject DB type exception [x86] - KVM_GUESTDBG_INJECT_BP: inject BP type exception [x86] - KVM_GUESTDBG_EXIT_PENDING: trigger an immediate guest exit [s390] @@ -2683,6 +2683,11 @@ updated to the correct (supplied) values. The second part of the structure is architecture specific and typically contains a set of debug registers. +For arm64 the number of debug registers is implementation defined and +can be determined by querying the KVM_CAP_GUEST_DEBUG_HW_BPS and +KVM_CAP_GUEST_DEBUG_HW_WPS capabilities which return a positive number +indicating the number of supported registers. + When debug events exit the main run loop with the reason KVM_EXIT_DEBUG with the kvm_debug_exit_arch part of the kvm_run structure containing architecture specific debug information. diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 461d288..6c745e0 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -116,13 +116,17 @@ struct kvm_vcpu_arch { * debugging the guest from the host and to maintain separate host and * guest state during world switches. vcpu_debug_state are the debug * registers of the vcpu as the guest sees them. host_debug_state are -* the host registers which are saved and restored during world switches. +* the host registers which are saved and restored during +* world switches. external_debug_state contains the debug +* values we want to debug the guest. This is set via the +* KVM_SET_GUEST_DEBUG ioctl. * * debug_ptr points to the set of debug registers that should be loaded * onto the hardware when running the guest. */ struct kvm_guest_debug_arch *debug_ptr; struct kvm_guest_debug_arch vcpu_deb
[PATCH v7 01/11] KVM: add comments for kvm_debug_exit_arch struct
Bring into line with the comments for the other structures and their KVM_EXIT_* cases. Also update api.txt to reflect use in kvm_run documentation. Signed-off-by: Alex Bennée Reviewed-by: David Hildenbrand Reviewed-by: Andrew Jones Acked-by: Christoffer Dall --- v2 - add comments for other exit types v3 - s/commentary/comments/ - add rb tags - update api.txt kvm_run to include KVM_EXIT_DEBUG desc v4 - sp fixes - add a-b --- Documentation/virtual/kvm/api.txt | 4 +++- include/uapi/linux/kvm.h | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 9fa2bf8..c34c32d 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -3070,11 +3070,13 @@ data_offset describes where the data is located (KVM_EXIT_IO_OUT) or where kvm expects application code to place the data for the next KVM_RUN invocation (KVM_EXIT_IO_IN). Data format is a packed array. + /* KVM_EXIT_DEBUG */ struct { struct kvm_debug_exit_arch arch; } debug; -Unused. +If the exit_reason is KVM_EXIT_DEBUG, then a vcpu is processing a debug event +for which architecture specific information is returned. /* KVM_EXIT_MMIO */ struct { diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 4b60056..70ac641 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -237,6 +237,7 @@ struct kvm_run { __u32 count; __u64 data_offset; /* relative to kvm_run start */ } io; + /* KVM_EXIT_DEBUG */ struct { struct kvm_debug_exit_arch arch; } debug; @@ -285,6 +286,7 @@ struct kvm_run { __u32 data; __u8 is_write; } dcr; + /* KVM_EXIT_INTERNAL_ERROR */ struct { __u32 suberror; /* Available with KVM_CAP_INTERNAL_ERROR_DATA: */ @@ -295,6 +297,7 @@ struct kvm_run { struct { __u64 gprs[32]; } osi; + /* KVM_EXIT_PAPR_HCALL */ struct { __u64 nr; __u64 ret; -- 2.4.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v7 03/11] KVM: arm: guest debug, add stub KVM_SET_GUEST_DEBUG ioctl
This commit adds a stub function to support the KVM_SET_GUEST_DEBUG ioctl. Any unsupported flag will return -EINVAL. For now, only KVM_GUESTDBG_ENABLE is supported, although it won't have any effects. Signed-off-by: Alex Bennée . Reviewed-by: Christoffer Dall --- v2 - simplified form of the ioctl (stuff will go into setup_debug) v3 - KVM_GUESTDBG_VALID->KVM_GUESTDBG_VALID_MASK - move mask check to the top of function - add ioctl doc header - split capability into separate patch - tweaked commit wording w.r.t return of -EINVAL v4 - add r-b-tag v7 - moved ioctl to arm64/kvm/guest.c, stubbed arm/kvm/guest.c --- Documentation/virtual/kvm/api.txt | 2 +- arch/arm/kvm/arm.c| 7 --- arch/arm/kvm/guest.c | 6 ++ arch/arm64/kvm/guest.c| 27 +++ 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index c34c32d..ba635c7 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2645,7 +2645,7 @@ handled. 4.87 KVM_SET_GUEST_DEBUG Capability: KVM_CAP_SET_GUEST_DEBUG -Architectures: x86, s390, ppc +Architectures: x86, s390, ppc, arm64 Type: vcpu ioctl Parameters: struct kvm_guest_debug (in) Returns: 0 on success; -1 on error diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index d9631ec..92b80bc 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -302,13 +302,6 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) kvm_arm_set_running_vcpu(NULL); } -int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, - struct kvm_guest_debug *dbg) -{ - return -EINVAL; -} - - int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, struct kvm_mp_state *mp_state) { diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c index d503fbb..96e935b 100644 --- a/arch/arm/kvm/guest.c +++ b/arch/arm/kvm/guest.c @@ -290,3 +290,9 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, { return -EINVAL; } + +int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, + struct kvm_guest_debug *dbg) +{ + return -EINVAL; +} diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 9535bd5..0ba8677 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -331,3 +331,30 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, { return -EINVAL; } + +#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE) + +/** + * kvm_arch_vcpu_ioctl_set_guest_debug - set up guest debugging + * @kvm: pointer to the KVM struct + * @kvm_guest_debug: the ioctl data buffer + * + * This sets up and enables the VM for guest debugging. Userspace + * passes in a control flag to enable different debug types and + * potentially other architecture specific information in the rest of + * the structure. + */ +int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, + struct kvm_guest_debug *dbg) +{ + if (dbg->control & ~KVM_GUESTDBG_VALID_MASK) + return -EINVAL; + + if (dbg->control & KVM_GUESTDBG_ENABLE) { + vcpu->guest_debug = dbg->control; + } else { + /* If not enabled clear all flags */ + vcpu->guest_debug = 0; + } + return 0; +} -- 2.4.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v7 08/11] KVM: arm64: introduce vcpu->arch.debug_ptr
This introduces a level of indirection for the debug registers. Instead of using the sys_regs[] directly we store registers in a structure in the vcpu. The new kvm_arm_reset_debug_ptr() sets the debug ptr to the guest context. This also entails updating the sys_regs code to access this new structure. New access function have been added for each set of debug registers. The generic functions are still used for the few registers stored in the main context. New access function pointers have been added to the sys_reg_desc structure to support the GET/SET_ONE_REG ioctl operations. Signed-off-by: Alex Bennée --- v6: - fix up some ws issues - correct clobber info - re-word commentary in kvm_host.h - fix endian access issues for aarch32 fields - revert all KVM_GET/SET_ONE_REG to 64bit (also see ABI update) v7 - new fn kvm_arm_reset_debug_ptr(), stubbed for arm - split trap fns into bcr,bvr,bcr,wvr and wxvr - add set/get fns to sys_regs_desc - reg_to_dbg/dbg_to_reg helpers for 32bit support --- arch/arm/include/asm/kvm_host.h | 2 +- arch/arm/kvm/arm.c| 2 + arch/arm64/include/asm/kvm_asm.h | 24 ++-- arch/arm64/include/asm/kvm_host.h | 17 ++- arch/arm64/kernel/asm-offsets.c | 6 + arch/arm64/kvm/debug.c| 9 ++ arch/arm64/kvm/hyp.S | 24 ++-- arch/arm64/kvm/sys_regs.c | 281 ++ arch/arm64/kvm/sys_regs.h | 6 + 9 files changed, 321 insertions(+), 50 deletions(-) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 746c0c69..f42759b 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -239,5 +239,5 @@ static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} static inline void kvm_arm_init_debug(void) {} static inline void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) {} static inline void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) {} - +static inline void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu) {} #endif /* __ARM_KVM_HOST_H__ */ diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index af60e6f..525473f 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -279,6 +279,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) /* Set up the timer */ kvm_timer_vcpu_init(vcpu); + kvm_arm_reset_debug_ptr(vcpu); + return 0; } diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index d6b507e..e997404 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -46,24 +46,16 @@ #defineCNTKCTL_EL1 20 /* Timer Control Register (EL1) */ #definePAR_EL1 21 /* Physical Address Register */ #define MDSCR_EL1 22 /* Monitor Debug System Control Register */ -#define DBGBCR0_EL123 /* Debug Breakpoint Control Registers (0-15) */ -#define DBGBCR15_EL1 38 -#define DBGBVR0_EL139 /* Debug Breakpoint Value Registers (0-15) */ -#define DBGBVR15_EL1 54 -#define DBGWCR0_EL155 /* Debug Watchpoint Control Registers (0-15) */ -#define DBGWCR15_EL1 70 -#define DBGWVR0_EL171 /* Debug Watchpoint Value Registers (0-15) */ -#define DBGWVR15_EL1 86 -#define MDCCINT_EL187 /* Monitor Debug Comms Channel Interrupt Enable Reg */ +#define MDCCINT_EL123 /* Monitor Debug Comms Channel Interrupt Enable Reg */ /* 32bit specific registers. Keep them at the end of the range */ -#defineDACR32_EL2 88 /* Domain Access Control Register */ -#defineIFSR32_EL2 89 /* Instruction Fault Status Register */ -#defineFPEXC32_EL2 90 /* Floating-Point Exception Control Register */ -#defineDBGVCR32_EL291 /* Debug Vector Catch Register */ -#defineTEECR32_EL1 92 /* ThumbEE Configuration Register */ -#defineTEEHBR32_EL193 /* ThumbEE Handler Base Register */ -#defineNR_SYS_REGS 94 +#defineDACR32_EL2 24 /* Domain Access Control Register */ +#defineIFSR32_EL2 25 /* Instruction Fault Status Register */ +#defineFPEXC32_EL2 26 /* Floating-Point Exception Control Register */ +#defineDBGVCR32_EL227 /* Debug Vector Catch Register */ +#defineTEECR32_EL1 28 /* ThumbEE Configuration Register */ +#defineTEEHBR32_EL129 /* ThumbEE Handler Base Register */ +#defineNR_SYS_REGS 30 /* 32bit mapping */ #define c0_MPIDR (MPIDR_EL1 * 2) /* MultiProcessor ID Register */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index e2db6a6..461d288 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -108,11 +108,25 @@ struct kvm_vcpu_arch { /* Exception Information */ struct kvm_vcpu_fault_info fault; - /* Debug state */ + /* Guest debug state
[PATCH v7 10/11] KVM: arm64: enable KVM_CAP_SET_GUEST_DEBUG
Finally advertise the KVM capability for SET_GUEST_DEBUG. Once arm support is added this check can be moved to the common kvm_vm_ioctl_check_extension() code. Signed-off-by: Alex Bennée Acked-by: Christoffer Dall --- v3: - separated capability check from previous patches - moved into arm64 specific ioctl handler. v4: - add a-b-tag --- arch/arm64/kvm/reset.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index 21d5a62..88e5331 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -76,6 +76,9 @@ int kvm_arch_dev_ioctl_check_extension(long ext) case KVM_CAP_GUEST_DEBUG_HW_WPS: r = get_num_wrps(); break; + case KVM_CAP_SET_GUEST_DEBUG: + r = 1; + break; default: r = 0; } -- 2.4.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v7 09/11] KVM: arm64: guest debug, HW assisted debug support
This adds support for userspace to control the HW debug registers for guest debug. In the debug ioctl we copy an IMPDEF registers into a new register set called host_debug_state. We use the recently introduced vcpu parameter debug_ptr to select which register set is copied into the real registers when world switch occurs. I've made some helper functions from hw_breakpoint.c more widely available for re-use. As with single step we need to tweak the guest registers to enable the exceptions so we need to save and restore those bits. Two new capabilities have been added to the KVM_EXTENSION ioctl to allow userspace to query the number of hardware break and watch points available on the host hardware. Signed-off-by: Alex Bennée Reviewed-by: Christoffer Dall --- v2 - switched to C setup - replace host debug registers directly into context - minor tweak to api docs - setup right register for debug - add FAR_EL2 to debug exit structure - add support for trapping debug register access v3 - remove stray trace statement - fix spacing around operators (various) - clean-up usage of trap_debug - introduce debug_ptr, replace excessive memcpy stuff - don't use memcpy in ioctl, just assign - update cap ioctl documentation - reword a number comments - rename host_debug_state->external_debug_state v4 - use the new u32/u64 split debug_ptr approach - fix some wording/comments v5 - don't set MDSCR_EL1.KDE (not needed) v6 - update wording given change in commentary - KVM_GUESTDBG_USE_HW_BP->KVM_GUESTDBG_USE_HW v7 - fix merge conflicts from ioctl move to guest.c - use kvm_arm_reset_debug_ptr to reset ptr - a BUG_ON() test has been added to trap failure to reset debug_ptr - debugging->debug in kvm_host.h comment - s/defined// s/to// in commit msg - rm ref to introducing debug_ptr in commit msg - add r-b tag --- Documentation/virtual/kvm/api.txt | 7 +- arch/arm64/include/asm/hw_breakpoint.h | 4 arch/arm64/include/asm/kvm_host.h | 6 - arch/arm64/kernel/hw_breakpoint.c | 4 ++-- arch/arm64/kvm/debug.c | 40 +- arch/arm64/kvm/guest.c | 7 ++ arch/arm64/kvm/handle_exit.c | 6 + arch/arm64/kvm/reset.c | 12 ++ arch/arm64/kvm/sys_regs.c | 3 --- include/uapi/linux/kvm.h | 2 ++ 10 files changed, 79 insertions(+), 12 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 33c8143..ada57df 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2668,7 +2668,7 @@ The top 16 bits of the control field are architecture specific control flags which can include the following: - KVM_GUESTDBG_USE_SW_BP: using software breakpoints [x86, arm64] - - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390] + - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390, arm64] - KVM_GUESTDBG_INJECT_DB: inject DB type exception [x86] - KVM_GUESTDBG_INJECT_BP: inject BP type exception [x86] - KVM_GUESTDBG_EXIT_PENDING: trigger an immediate guest exit [s390] @@ -2683,6 +2683,11 @@ updated to the correct (supplied) values. The second part of the structure is architecture specific and typically contains a set of debug registers. +For arm64 the number of debug registers is implementation defined and +can be determined by querying the KVM_CAP_GUEST_DEBUG_HW_BPS and +KVM_CAP_GUEST_DEBUG_HW_WPS capabilities which return a positive number +indicating the number of supported registers. + When debug events exit the main run loop with the reason KVM_EXIT_DEBUG with the kvm_debug_exit_arch part of the kvm_run structure containing architecture specific debug information. diff --git a/arch/arm64/include/asm/hw_breakpoint.h b/arch/arm64/include/asm/hw_breakpoint.h index 52b484b..9da2824 100644 --- a/arch/arm64/include/asm/hw_breakpoint.h +++ b/arch/arm64/include/asm/hw_breakpoint.h @@ -130,6 +130,10 @@ static inline void ptrace_hw_copy_thread(struct task_struct *task) } #endif +/* Determine number of BRP/WRP registers available. */ +extern int get_num_brps(void); +extern int get_num_wrps(void); + extern struct pmu perf_ops_bp; #endif /* __KERNEL__ */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 461d288..6c745e0 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -116,13 +116,17 @@ struct kvm_vcpu_arch { * debugging the guest from the host and to maintain separate host and * guest state during world switches. vcpu_debug_state are the debug * registers of the vcpu as the guest sees them. host_debug_state are -* the host registers which are saved and restored during world switches. +* the host registers which are s
[PATCH v7 11/11] KVM: arm64: add trace points for guest_debug debug
This includes trace points for: kvm_arch_setup_guest_debug kvm_arch_clear_guest_debug I've also added some generic register setting trace events and also a trace point to dump the array of hardware registers. Signed-off-by: Alex Bennée --- v3 - add trace event for debug access. - remove short trace #define, rename trace events - use __print_array with fixed array instead of own func - rationalise trace points (only one per register changed) - add vcpu ptr to the debug_setup trace - remove :: in prints v4 - u32/u64 split on debug registers - fix for renames - add tracing of traps/set_guest_debug - remove handle_guest_debug trace v5 - minor print fmt fix - rm pstate traces v6 - fix merge conflicts - update control reg tracking to u64 (abi change) v7 - fix merge conflicts from ioctl move - fix other minor merge conflicts - fixes for the re-factored sys_regs code --- arch/arm64/kvm/debug.c| 35 - arch/arm64/kvm/guest.c| 4 ++ arch/arm64/kvm/sys_regs.c | 21 arch/arm64/kvm/trace.h| 123 ++ 4 files changed, 182 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index 46b73d7..119107f 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -24,6 +24,8 @@ #include #include +#include "trace.h" + /* These are the bits of MDSCR_EL1 we may manipulate */ #define MDSCR_EL1_DEBUG_MASK (DBG_MDSCR_SS | \ DBG_MDSCR_KDE | \ @@ -44,11 +46,17 @@ static DEFINE_PER_CPU(u32, mdcr_el2); static void save_guest_debug_regs(struct kvm_vcpu *vcpu) { vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1); + + trace_kvm_arm_set_dreg32("Saved MDSCR_EL1", + vcpu->arch.guest_debug_preserved.mdscr_el1); } static void restore_guest_debug_regs(struct kvm_vcpu *vcpu) { vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1; + + trace_kvm_arm_set_dreg32("Restored MDSCR_EL1", + vcpu_sys_reg(vcpu, MDSCR_EL1)); } /** @@ -99,6 +107,8 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) { bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY); + trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug); + vcpu->arch.mdcr_el2 = __this_cpu_read(mdcr_el2) & MDCR_EL2_HPMN_MASK; vcpu->arch.mdcr_el2 |= (MDCR_EL2_TPM | MDCR_EL2_TPMCR | @@ -140,6 +150,8 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) vcpu_sys_reg(vcpu, MDSCR_EL1) &= ~DBG_MDSCR_SS; } + trace_kvm_arm_set_dreg32("SPSR_EL2", *vcpu_cpsr(vcpu)); + /* * HW Breakpoints and watchpoints * @@ -156,6 +168,14 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) vcpu->arch.debug_ptr = &vcpu->arch.external_debug_state; vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; trap_debug = true; + + trace_kvm_arm_set_regset("BKPTS", get_num_brps(), + &vcpu->arch.debug_ptr->dbg_bcr[0], + &vcpu->arch.debug_ptr->dbg_bvr[0]); + + trace_kvm_arm_set_regset("WAPTS", get_num_wrps(), + &vcpu->arch.debug_ptr->dbg_wcr[0], + &vcpu->arch.debug_ptr->dbg_wvr[0]); } } @@ -165,10 +185,15 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) /* Trap debug register access */ if (trap_debug) vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA; + + trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2); + trace_kvm_arm_set_dreg32("MDSCR_EL1", vcpu_sys_reg(vcpu, MDSCR_EL1)); } void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) { + trace_kvm_arm_clear_debug(vcpu->guest_debug); + if (vcpu->guest_debug) { restore_guest_debug_regs(vcpu); @@ -176,8 +201,16 @@ void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) * If we were using HW debug we need to restore the * debug_ptr to the guest debug state. */ - if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) + if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) { kvm_arm_reset_debug_ptr(vcpu); + trace_kvm_arm_set_regset("BKPTS", get_num_brps(), + &vcpu->arch.debug_ptr->dbg_bcr[0], +
[PATCH v7 06/11] KVM: arm64: guest debug, add support for single-step
This adds support for single-stepping the guest. To do this we need to manipulate the guests PSTATE.SS and MDSCR_EL1.SS bits to trigger stepping. We take care to preserve MDSCR_EL1 and trap access to it to ensure we don't affect the apparent state of the guest. As we have to enable trapping of all software debug exceptions we suppress the ability of the guest to single-step itself. If we didn't we would have to deal with the exception arriving while the guest was in kernelspace when the guest is expecting to single-step userspace. This is something we don't want to unwind in the kernel. Once the host is no longer debugging the guest its ability to single-step userspace is restored. Signed-off-by: Alex Bennée Reviewed-by: Christoffer Dall --- v2 - Move pstate/mdscr manipulation into C - don't export guest_debug to assembly - add accessor for saved_debug regs - tweak save/restore of mdscr_el1 v3 - don't save PC in debug information struct - rename debug_saved_regs->guest_debug_state - save whole value, only use bits in restore - add save/restore_guest-debug_regs helper functions - simplify commit message for clarity - rm vcpu_debug_saved_reg access fn v4 - added more comments based on suggestions - guest_debug_state->guest_debug_preserved - no point masking restore, we will trap out v5 - more comments - don't bother preserving pstate.ss (guest never sees change) v6 - reword comments on guest SS suppression - simplify comment for save regs, SS explained in detail later on - add r-b-t (code) - expanded commit description v7 - merge fix for ioctl move to guest.c --- arch/arm64/include/asm/kvm_host.h | 11 +++ arch/arm64/kvm/debug.c| 68 --- arch/arm64/kvm/guest.c| 4 ++- arch/arm64/kvm/handle_exit.c | 2 ++ 4 files changed, 80 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 7cb99b5..e2db6a6 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -123,6 +123,17 @@ struct kvm_vcpu_arch { * here. */ + /* +* Guest registers we preserve during guest debugging. +* +* These shadow registers are updated by the kvm_handle_sys_reg +* trap handler if the guest accesses or updates them while we +* are using guest debug. +*/ + struct { + u32 mdscr_el1; + } guest_debug_preserved; + /* Don't run the guest */ bool pause; diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index 8d1bfa4..d439eb8 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -19,11 +19,39 @@ #include +#include +#include #include +#include + +/* These are the bits of MDSCR_EL1 we may manipulate */ +#define MDSCR_EL1_DEBUG_MASK (DBG_MDSCR_SS | \ + DBG_MDSCR_KDE | \ + DBG_MDSCR_MDE) static DEFINE_PER_CPU(u32, mdcr_el2); /** + * save/restore_guest_debug_regs + * + * For some debug operations we need to tweak some guest registers. As + * a result we need to save the state of those registers before we + * make those modifications. + * + * Guest access to MDSCR_EL1 is trapped by the hypervisor and handled + * after we have restored the preserved value to the main context. + */ +static void save_guest_debug_regs(struct kvm_vcpu *vcpu) +{ + vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1); +} + +static void restore_guest_debug_regs(struct kvm_vcpu *vcpu) +{ + vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1; +} + +/** * kvm_arm_init_debug - grab what we need for debug * * Currently the sole task of this function is to retrieve the initial @@ -38,7 +66,6 @@ void kvm_arm_init_debug(void) __this_cpu_write(mdcr_el2, kvm_call_hyp(__kvm_get_mdcr_el2)); } - /** * kvm_arm_setup_debug - set up debug related stuff * @@ -73,12 +100,45 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) if (trap_debug) vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA; - /* Trap breakpoints? */ - if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) + /* Is Guest debugging in effect? */ + if (vcpu->guest_debug) { + /* Route all software debug exceptions to EL2 */ vcpu->arch.mdcr_el2 |= MDCR_EL2_TDE; + + /* Save guest debug state */ + save_guest_debug_regs(vcpu); + + /* +* Single Step (ARM ARM D2.12.3 The software step state +* machine) +* +* If we are doing Single Step we need to manipulate +* the guest's MDSCR_EL1.SS and PSTATE.SS. Once the +* step has occurred the hypervisor will tr
[PATCH v7 05/11] KVM: arm64: guest debug, add SW break point support
This adds support for SW breakpoints inserted by userspace. We do this by trapping all guest software debug exceptions to the hypervisor (MDCR_EL2.TDE). The exit handler sets an exit reason of KVM_EXIT_DEBUG with the kvm_debug_exit_arch structure holding the exception syndrome information. It will be up to userspace to extract the PC (via GET_ONE_REG) and determine if the debug event was for a breakpoint it inserted. If not userspace will need to re-inject the correct exception restart the hypervisor to deliver the debug exception to the guest. Any other guest software debug exception (e.g. single step or HW assisted breakpoints) will cause an error and the VM to be killed. This is addressed by later patches which add support for the other debug types. Signed-off-by: Alex Bennée Reviewed-by: Christoffer Dall --- v2 - update to use new exit struct - tweak for C setup - do our setup in debug_setup/clear code - fixed up comments v3: - fix spacing in KVM_GUESTDBG_VALID_MASK - fix and clarify wording on kvm_handle_guest_debug - handle error case in kvm_handle_guest_debug - re-word the commit message v4 - rm else leg - add r-b-tag v7 - moved ioctl to guest --- Documentation/virtual/kvm/api.txt | 2 +- arch/arm64/kvm/debug.c| 3 +++ arch/arm64/kvm/guest.c| 2 +- arch/arm64/kvm/handle_exit.c | 36 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index ba635c7..33c8143 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2667,7 +2667,7 @@ when running. Common control bits are: The top 16 bits of the control field are architecture specific control flags which can include the following: - - KVM_GUESTDBG_USE_SW_BP: using software breakpoints [x86] + - KVM_GUESTDBG_USE_SW_BP: using software breakpoints [x86, arm64] - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390] - KVM_GUESTDBG_INJECT_DB: inject DB type exception [x86] - KVM_GUESTDBG_INJECT_BP: inject BP type exception [x86] diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index faf0e1f..8d1bfa4 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -73,6 +73,9 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) if (trap_debug) vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA; + /* Trap breakpoints? */ + if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) + vcpu->arch.mdcr_el2 |= MDCR_EL2_TDE; } void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 0ba8677..22d22c5 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -332,7 +332,7 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, return -EINVAL; } -#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE) +#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP) /** * kvm_arch_vcpu_ioctl_set_guest_debug - set up guest debugging diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 524fa25..27f38a9 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -82,6 +82,40 @@ static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run) return 1; } +/** + * kvm_handle_guest_debug - handle a debug exception instruction + * + * @vcpu: the vcpu pointer + * @run: access to the kvm_run structure for results + * + * We route all debug exceptions through the same handler. If both the + * guest and host are using the same debug facilities it will be up to + * userspace to re-inject the correct exception for guest delivery. + * + * @return: 0 (while setting run->exit_reason), -1 for error + */ +static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + u32 hsr = kvm_vcpu_get_hsr(vcpu); + int ret = 0; + + run->exit_reason = KVM_EXIT_DEBUG; + run->debug.arch.hsr = hsr; + + switch (hsr >> ESR_ELx_EC_SHIFT) { + case ESR_ELx_EC_BKPT32: + case ESR_ELx_EC_BRK64: + break; + default: + kvm_err("%s: un-handled case hsr: %#08x\n", + __func__, (unsigned int) hsr); + ret = -1; + break; + } + + return ret; +} + static exit_handle_fn arm_exit_handlers[] = { [ESR_ELx_EC_WFx]= kvm_handle_wfx, [ESR_ELx_EC_CP15_32]= kvm_handle_cp15_32, @@ -96,6 +130,8 @@ static exit_handle_fn arm_exit_handlers[] = { [ESR_ELx_EC_SYS64] = kvm_handle_sys_reg, [ESR_ELx_EC_IABT_LOW] = kvm_handle_guest_abort, [ESR_ELx_EC_DABT_LOW] = kvm_handle_guest_abort, + [ESR_ELx_EC_BKPT32] = kvm_handle_guest_debug, + [ESR_ELx_EC_BRK64] = kvm_handle_guest_debug, }; static exit
[PATCH v7 04/11] KVM: arm: introduce kvm_arm_init/setup/clear_debug
This is a precursor for later patches which will need to do more to setup debug state before entering the hyp.S switch code. The existing functionality for setting mdcr_el2 has been moved out of hyp.S and now uses the value kept in vcpu->arch.mdcr_el2. As the assembler used to previously mask and preserve MDCR_EL2.HPMN I've had to add a mechanism to save the value of mdcr_el2 as a per-cpu variable during the initialisation code. The kernel never sets this number so we are assuming the bootcode has set up the correct value here. This also moves the conditional setting of the TDA bit from the hyp code into the C code which is currently used for the lazy debug register context switch code. Signed-off-by: Alex Bennée Reviewed-by: Christoffer Dall --- v3 - rename fns from arch->arm - preserve MDCR_EL2.HPMN setting - re-word some of the comments - fix some minor grammar nits - merge setting of mdcr_el2 - introduce trap_debug flag - move setup/clear within the irq lock section v4 - fix TDOSA desc - rm un-needed else leg - s/arch/arm/ v6 - add s-o-b tag --- arch/arm/include/asm/kvm_host.h | 4 ++ arch/arm/kvm/arm.c| 9 - arch/arm64/include/asm/kvm_asm.h | 2 + arch/arm64/include/asm/kvm_host.h | 5 +++ arch/arm64/kernel/asm-offsets.c | 1 + arch/arm64/kvm/Makefile | 2 +- arch/arm64/kvm/debug.c| 81 +++ arch/arm64/kvm/hyp.S | 19 - 8 files changed, 110 insertions(+), 13 deletions(-) create mode 100644 arch/arm64/kvm/debug.c diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index d71607c..746c0c69 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -236,4 +236,8 @@ 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) {} +static inline void kvm_arm_init_debug(void) {} +static inline void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) {} +static inline void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) {} + #endif /* __ARM_KVM_HOST_H__ */ diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 92b80bc..af60e6f 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -542,6 +542,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) continue; } + kvm_arm_setup_debug(vcpu); + /** * Enter the guest */ @@ -554,7 +556,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) vcpu->mode = OUTSIDE_GUEST_MODE; kvm_guest_exit(); trace_kvm_exit(kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu)); - /* + + kvm_arm_clear_debug(vcpu); + +/* * We may have taken a host interrupt in HYP mode (ie * while executing the guest). This interrupt is still * pending, as we haven't serviced it yet! @@ -902,6 +907,8 @@ static void cpu_init_hyp_mode(void *dummy) vector_ptr = (unsigned long)__kvm_hyp_vector; __cpu_init_hyp_mode(boot_pgd_ptr, pgd_ptr, hyp_stack_ptr, vector_ptr); + + kvm_arm_init_debug(); } static int hyp_init_cpu_notify(struct notifier_block *self, diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index 4f7310f..d6b507e 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -137,6 +137,8 @@ extern char __restore_vgic_v2_state[]; extern char __save_vgic_v3_state[]; extern char __restore_vgic_v3_state[]; +extern u32 __kvm_get_mdcr_el2(void); + #endif #endif /* __ARM_KVM_ASM_H__ */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index f0f58c9..7cb99b5 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -103,6 +103,7 @@ struct kvm_vcpu_arch { /* HYP configuration */ u64 hcr_el2; + u32 mdcr_el2; /* Exception Information */ struct kvm_vcpu_fault_info fault; @@ -250,4 +251,8 @@ 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) {} +void kvm_arm_init_debug(void); +void kvm_arm_setup_debug(struct kvm_vcpu *vcpu); +void kvm_arm_clear_debug(struct kvm_vcpu *vcpu); + #endif /* __ARM64_KVM_HOST_H__ */ diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index da675cc..dfb25a2 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -117,6 +117,7 @@ int main(void) DEFINE(VCPU_HPFAR_EL2, offsetof(struct kvm_vcpu, a
[PATCH v7 07/11] KVM: arm64: re-factor hyp.S debug register code
This is a pre-cursor to sharing the code with the guest debug support. This replaces the big macro that fishes data out of a fixed location with a more general helper macro to restore a set of debug registers. It uses macro substitution so it can be re-used for debug control and value registers. It does however rely on the debug registers being 64 bit aligned (as they happen to be in the hyp ABI). Signed-off-by: Alex Bennée Reviewed-by: Christoffer Dall --- v3: - return to the patch series - add save and restore targets - change register use and document v4: - keep original setup/restore names - don't use split u32/u64 structure yet v6: - fix ws and clobber info in hyp.S v7: - fix whitespace - add r-b-tag --- arch/arm64/kvm/hyp.S | 517 ++- 1 file changed, 138 insertions(+), 379 deletions(-) diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S index 2c67a14..77c08df 100644 --- a/arch/arm64/kvm/hyp.S +++ b/arch/arm64/kvm/hyp.S @@ -228,199 +228,52 @@ stp x24, x25, [x3, #160] .endm -.macro save_debug - // x2: base address for cpu context - // x3: tmp register - - mrs x26, id_aa64dfr0_el1 - ubfxx24, x26, #12, #4 // Extract BRPs - ubfxx25, x26, #20, #4 // Extract WRPs - mov w26, #15 - sub w24, w26, w24 // How many BPs to skip - sub w25, w26, w25 // How many WPs to skip - - add x3, x2, #CPU_SYSREG_OFFSET(DBGBCR0_EL1) - - adr x26, 1f - add x26, x26, x24, lsl #2 - br x26 -1: - mrs x20, dbgbcr15_el1 - mrs x19, dbgbcr14_el1 - mrs x18, dbgbcr13_el1 - mrs x17, dbgbcr12_el1 - mrs x16, dbgbcr11_el1 - mrs x15, dbgbcr10_el1 - mrs x14, dbgbcr9_el1 - mrs x13, dbgbcr8_el1 - mrs x12, dbgbcr7_el1 - mrs x11, dbgbcr6_el1 - mrs x10, dbgbcr5_el1 - mrs x9, dbgbcr4_el1 - mrs x8, dbgbcr3_el1 - mrs x7, dbgbcr2_el1 - mrs x6, dbgbcr1_el1 - mrs x5, dbgbcr0_el1 - - adr x26, 1f - add x26, x26, x24, lsl #2 - br x26 - -1: - str x20, [x3, #(15 * 8)] - str x19, [x3, #(14 * 8)] - str x18, [x3, #(13 * 8)] - str x17, [x3, #(12 * 8)] - str x16, [x3, #(11 * 8)] - str x15, [x3, #(10 * 8)] - str x14, [x3, #(9 * 8)] - str x13, [x3, #(8 * 8)] - str x12, [x3, #(7 * 8)] - str x11, [x3, #(6 * 8)] - str x10, [x3, #(5 * 8)] - str x9, [x3, #(4 * 8)] - str x8, [x3, #(3 * 8)] - str x7, [x3, #(2 * 8)] - str x6, [x3, #(1 * 8)] - str x5, [x3, #(0 * 8)] - - add x3, x2, #CPU_SYSREG_OFFSET(DBGBVR0_EL1) - - adr x26, 1f - add x26, x26, x24, lsl #2 - br x26 -1: - mrs x20, dbgbvr15_el1 - mrs x19, dbgbvr14_el1 - mrs x18, dbgbvr13_el1 - mrs x17, dbgbvr12_el1 - mrs x16, dbgbvr11_el1 - mrs x15, dbgbvr10_el1 - mrs x14, dbgbvr9_el1 - mrs x13, dbgbvr8_el1 - mrs x12, dbgbvr7_el1 - mrs x11, dbgbvr6_el1 - mrs x10, dbgbvr5_el1 - mrs x9, dbgbvr4_el1 - mrs x8, dbgbvr3_el1 - mrs x7, dbgbvr2_el1 - mrs x6, dbgbvr1_el1 - mrs x5, dbgbvr0_el1 - - adr x26, 1f - add x26, x26, x24, lsl #2 - br x26 - -1: - str x20, [x3, #(15 * 8)] - str x19, [x3, #(14 * 8)] - str x18, [x3, #(13 * 8)] - str x17, [x3, #(12 * 8)] - str x16, [x3, #(11 * 8)] - str x15, [x3, #(10 * 8)] - str x14, [x3, #(9 * 8)] - str x13, [x3, #(8 * 8)] - str x12, [x3, #(7 * 8)] - str x11, [x3, #(6 * 8)] - str x10, [x3, #(5 * 8)] - str x9, [x3, #(4 * 8)] - str x8, [x3, #(3 * 8)] - str x7, [x3, #(2 * 8)] - str x6, [x3, #(1 * 8)] - str x5, [x3, #(0 * 8)] - - add x3, x2, #CPU_SYSREG_OFFSET(DBGWCR0_EL1) - - adr x26, 1f - add x26, x26, x25, lsl #2 - br x26 +.macro save_debug type + // x4: pointer to register set + // x5: number of registers to skip + // x6..x22 trashed + + adr x22, 1f + add x22, x22, x5, lsl #2 + br x22 1: - mrs x20, dbgwcr15_el1 - mrs x19, dbgwcr14_el1 - mrs x18, dbgwcr13_el1 - mrs x17, dbgwcr12_el1 - mrs x16, dbgwcr11_el1 - mrs x15, dbgwcr10_el1 - mrs x14, dbgwcr9_el1 - mrs x13, dbgwcr8_el1 - mrs x12, dbgwcr7_el1 - mrs x11, dbgwcr6_el1 - mrs x10, dbgwcr5_el1 - mrs x9, dbgwcr4_el1 - mrs x8, dbgwcr3_el1 - mrs x7, dbgwcr
[PATCH v7 02/11] KVM: arm64: guest debug, define API headers
This commit defines the API headers for guest debugging. There are two architecture specific debug structures: - kvm_guest_debug_arch, allows us to pass in HW debug registers - kvm_debug_exit_arch, signals exception and possible faulting address The type of debugging being used is controlled by the architecture specific control bits of the kvm_guest_debug->control flags in the ioctl structure. Signed-off-by: Alex Bennée Reviewed-by: David Hildenbrand Reviewed-by: Andrew Jones Acked-by: Christoffer Dall --- v2 - expose hsr and pc directly to user-space v3 - s/control/controlled/ in commit message - add v8 to ARM ARM comment (ARM Architecture Reference Manual) - add rb tag - rm pc, add far - re-word comments on alignment - rename KVM_ARM_NDBG_REGS -> KVM_ARM_MAX_DBG_REGS v4 - now uses common HW/SW BP define - add a-b-tag - use u32 for control regs v5 - revert to have arch specific KVM_GUESTDBG_USE_SW/HW_BP - rm stale comments dbgctrl was stored as u64 v6 - mv far comment from later patch - KVM_GUESTDBG_USE_HW_BP -> KVM_GUESTDBG_USE_HW - revert control regs to u64 (parity with GET/SET_ONE_REG) --- arch/arm64/include/uapi/asm/kvm.h | 27 +++ 1 file changed, 27 insertions(+) diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index d268320..d82f3f3 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -100,12 +100,39 @@ struct kvm_sregs { struct kvm_fpu { }; +/* + * See v8 ARM ARM D7.3: Debug Registers + * + * The architectural limit is 16 debug registers of each type although + * in practice there are usually less (see ID_AA64DFR0_EL1). + * + * Although the control registers are architecturally defined as 32 + * bits wide we use a 64 bit structure here to keep parity with + * KVM_GET/SET_ONE_REG behaviour which treats all system registers as + * 64 bit values. It also allows for the possibility of the + * architecture expanding the control registers without having to + * change the userspace ABI. + */ +#define KVM_ARM_MAX_DBG_REGS 16 struct kvm_guest_debug_arch { + __u64 dbg_bcr[KVM_ARM_MAX_DBG_REGS]; + __u64 dbg_bvr[KVM_ARM_MAX_DBG_REGS]; + __u64 dbg_wcr[KVM_ARM_MAX_DBG_REGS]; + __u64 dbg_wvr[KVM_ARM_MAX_DBG_REGS]; }; struct kvm_debug_exit_arch { + __u32 hsr; + __u64 far; /* used for watchpoints */ }; +/* + * Architecture specific defines for kvm_guest_debug->control + */ + +#define KVM_GUESTDBG_USE_SW_BP (1 << 16) +#define KVM_GUESTDBG_USE_HW(1 << 17) + struct kvm_sync_regs { }; -- 2.4.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v6 10/12] KVM: arm64: guest debug, HW assisted debug support
Christoffer Dall writes: > On Thu, Jun 25, 2015 at 07:38:33AM +0100, Alex Bennée wrote: >> >> Christoffer Dall writes: >> >> > On Fri, Jun 19, 2015 at 01:23:48PM +0100, Alex Bennée wrote: >> >> This adds support for userspace to control the HW debug registers for >> >> guest debug. In the debug ioctl we copy the IMPDEF defined number of >> >> void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) >> >> { >> >> - if (vcpu->guest_debug) >> >> + if (vcpu->guest_debug) { >> >> restore_guest_debug_regs(vcpu); >> >> + >> >> + /* >> >> + * If we were using HW debug we need to restore the >> >> + * debug_ptr to the guest debug state. >> >> + */ >> >> + if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) >> >> + vcpu->arch.debug_ptr = &vcpu->arch.vcpu_debug_state; >> > >> > I still think this would be more cleanly done in the setup_debug >> > function, but ok: >> >> I don't follow, setup_debug is called before we enter KVM. It's pretty >> light when no debugging is being done so this ensure we leave state how >> we would like it when we stop debugging. >> >> I can move it to an else leg in setup if you really want. >> > I just feel like whenever you enter the guest you setup the state you > want for your guest and then when reading the code you never have to > worry about "did I set the pointer back correctly last time it exited", > but thinking about your response, I guess that's an extra store on each > world-switch, so theoretically that may be a bit more overhead (on top > of the hundreds other stores and spinlocks we take and stuff). The setup/clear() calls are tightly paired around the KVM_RUN ioctl code without any obvious exit points. Are there any cases you can escape the ioctl code flow? I notice irq's are re-enabled so I guess a suitably determined irq function could change the return address or mess around with guest_debug. > If you prefer, leave it like this, but consider adding a > BUG_ON(!guest_debugging && debug_ptr != &vcpu->arch.vcpu_debug_state) in > the setup function... The clear_debug() code would end up being a fairly sparse piece of code without it ;-) > I'm probably being paranoid. A little paranoia goes a long way in kernel mode ;-) > > -Christoffer -- Alex Bennée -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v6 10/12] KVM: arm64: guest debug, HW assisted debug support
Christoffer Dall writes: > On Fri, Jun 19, 2015 at 01:23:48PM +0100, Alex Bennée wrote: >> This adds support for userspace to control the HW debug registers for >> guest debug. In the debug ioctl we copy the IMPDEF defined number of > > s/defined// > >> registers into a new register set called host_debug_state. There is now >> a new vcpu parameter called debug_ptr which selects which register set >> is to copied into the real registers when world switch occurs. > > But this patch doesn't seem to add the debug_ptr field? Oops, yes the comment belongs to the previous patch. > > s/to// > >> >> I've moved some helper functions into the hw_breakpoint.h header for >> re-use. >> >> As with single step we need to tweak the guest registers to enable the >> exceptions so we need to save and restore those bits. >> >> Two new capabilities have been added to the KVM_EXTENSION ioctl to allow >> userspace to query the number of hardware break and watch points >> available on the host hardware. >> >> Signed-off-by: Alex Bennée >> >> --- >> v2 >>- switched to C setup >>- replace host debug registers directly into context >>- minor tweak to api docs >>- setup right register for debug >>- add FAR_EL2 to debug exit structure >>- add support for trapping debug register access >> v3 >>- remove stray trace statement >>- fix spacing around operators (various) >>- clean-up usage of trap_debug >>- introduce debug_ptr, replace excessive memcpy stuff >>- don't use memcpy in ioctl, just assign >>- update cap ioctl documentation >>- reword a number comments >>- rename host_debug_state->external_debug_state >> v4 >>- use the new u32/u64 split debug_ptr approach >>- fix some wording/comments >> v5 >>- don't set MDSCR_EL1.KDE (not needed) >> v6 >>- update wording given change in commentary >>- KVM_GUESTDBG_USE_HW_BP->KVM_GUESTDBG_USE_HW >> --- >> Documentation/virtual/kvm/api.txt | 7 ++- >> arch/arm/kvm/arm.c | 7 +++ >> arch/arm64/include/asm/hw_breakpoint.h | 12 +++ >> arch/arm64/include/asm/kvm_host.h | 6 +- >> arch/arm64/kernel/hw_breakpoint.c | 12 --- >> arch/arm64/kvm/debug.c | 37 >> +- >> arch/arm64/kvm/handle_exit.c | 6 ++ >> arch/arm64/kvm/reset.c | 12 +++ >> include/uapi/linux/kvm.h | 2 ++ >> 9 files changed, 82 insertions(+), 19 deletions(-) >> >> diff --git a/Documentation/virtual/kvm/api.txt >> b/Documentation/virtual/kvm/api.txt >> index 33c8143..ada57df 100644 >> --- a/Documentation/virtual/kvm/api.txt >> +++ b/Documentation/virtual/kvm/api.txt >> @@ -2668,7 +2668,7 @@ The top 16 bits of the control field are architecture >> specific control >> flags which can include the following: >> >>- KVM_GUESTDBG_USE_SW_BP: using software breakpoints [x86, arm64] >> - - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390] >> + - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390, >> arm64] >>- KVM_GUESTDBG_INJECT_DB: inject DB type exception [x86] >>- KVM_GUESTDBG_INJECT_BP: inject BP type exception [x86] >>- KVM_GUESTDBG_EXIT_PENDING: trigger an immediate guest exit [s390] >> @@ -2683,6 +2683,11 @@ updated to the correct (supplied) values. >> The second part of the structure is architecture specific and >> typically contains a set of debug registers. >> >> +For arm64 the number of debug registers is implementation defined and >> +can be determined by querying the KVM_CAP_GUEST_DEBUG_HW_BPS and >> +KVM_CAP_GUEST_DEBUG_HW_WPS capabilities which return a positive number >> +indicating the number of supported registers. >> + >> When debug events exit the main run loop with the reason >> KVM_EXIT_DEBUG with the kvm_debug_exit_arch part of the kvm_run >> structure containing architecture specific debug information. >> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c >> index 0d17c7b..60c4045 100644 >> --- a/arch/arm/kvm/arm.c >> +++ b/arch/arm/kvm/arm.c >> @@ -307,6 +307,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) >> >> #define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE |\ >> KVM_GUESTDBG_USE_SW_BP | \ >> +KVM_GUESTDBG_USE_HW | \ >>
Re: [PATCH v6 08/12] KVM: arm64: re-factor hyp.S debug register code
Christoffer Dall writes: > On Fri, Jun 19, 2015 at 01:23:46PM +0100, Alex Bennée wrote: >> This is a pre-cursor to sharing the code with the guest debug support. >> This replaces the big macro that fishes data out of a fixed location >> with a more general helper macro to restore a set of debug registers. It >> uses macro substitution so it can be re-used for debug control and value >> registers. It does however rely on the debug registers being 64 bit >> aligned (as they happen to be in the hyp ABI). >> >> Signed-off-by: Alex Bennée >> >> --- >> v3: >> - return to the patch series >> - add save and restore targets >> - change register use and document >> v4: >> - keep original setup/restore names >> - don't use split u32/u64 structure yet >> v6: >> - fix ws and clobber info in hyp.S >> --- >> arch/arm64/kvm/hyp.S | 517 >> ++- >> 1 file changed, 138 insertions(+), 379 deletions(-) >> >> diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S >> index 74e63d8..ee7f649 100644 >> --- a/arch/arm64/kvm/hyp.S >> +++ b/arch/arm64/kvm/hyp.S >> @@ -228,199 +228,52 @@ >> stp x24, x25, [x3, #160] >> .endm >> >> -.macro save_debug >> -// x2: base address for cpu context >> -// x3: tmp register >> - >> -mrs x26, id_aa64dfr0_el1 >> -ubfxx24, x26, #12, #4 // Extract BRPs >> -ubfxx25, x26, #20, #4 // Extract WRPs >> -mov w26, #15 >> -sub w24, w26, w24 // How many BPs to skip >> -sub w25, w26, w25 // How many WPs to skip >> - >> -add x3, x2, #CPU_SYSREG_OFFSET(DBGBCR0_EL1) >> - >> -adr x26, 1f >> -add x26, x26, x24, lsl #2 >> -br x26 >> -1: >> -mrs x20, dbgbcr15_el1 >> -mrs x19, dbgbcr14_el1 >> -mrs x18, dbgbcr13_el1 >> -mrs x17, dbgbcr12_el1 >> -mrs x16, dbgbcr11_el1 >> -mrs x15, dbgbcr10_el1 >> -mrs x14, dbgbcr9_el1 >> -mrs x13, dbgbcr8_el1 >> -mrs x12, dbgbcr7_el1 >> -mrs x11, dbgbcr6_el1 >> -mrs x10, dbgbcr5_el1 >> -mrs x9, dbgbcr4_el1 >> -mrs x8, dbgbcr3_el1 >> -mrs x7, dbgbcr2_el1 >> -mrs x6, dbgbcr1_el1 >> -mrs x5, dbgbcr0_el1 >> - >> -adr x26, 1f >> -add x26, x26, x24, lsl #2 >> -br x26 >> - >> -1: >> -str x20, [x3, #(15 * 8)] >> -str x19, [x3, #(14 * 8)] >> -str x18, [x3, #(13 * 8)] >> -str x17, [x3, #(12 * 8)] >> -str x16, [x3, #(11 * 8)] >> -str x15, [x3, #(10 * 8)] >> -str x14, [x3, #(9 * 8)] >> -str x13, [x3, #(8 * 8)] >> -str x12, [x3, #(7 * 8)] >> -str x11, [x3, #(6 * 8)] >> -str x10, [x3, #(5 * 8)] >> -str x9, [x3, #(4 * 8)] >> -str x8, [x3, #(3 * 8)] >> -str x7, [x3, #(2 * 8)] >> -str x6, [x3, #(1 * 8)] >> -str x5, [x3, #(0 * 8)] >> - >> -add x3, x2, #CPU_SYSREG_OFFSET(DBGBVR0_EL1) >> - >> -adr x26, 1f >> -add x26, x26, x24, lsl #2 >> -br x26 >> -1: >> -mrs x20, dbgbvr15_el1 >> -mrs x19, dbgbvr14_el1 >> -mrs x18, dbgbvr13_el1 >> -mrs x17, dbgbvr12_el1 >> -mrs x16, dbgbvr11_el1 >> -mrs x15, dbgbvr10_el1 >> -mrs x14, dbgbvr9_el1 >> -mrs x13, dbgbvr8_el1 >> -mrs x12, dbgbvr7_el1 >> -mrs x11, dbgbvr6_el1 >> -mrs x10, dbgbvr5_el1 >> -mrs x9, dbgbvr4_el1 >> -mrs x8, dbgbvr3_el1 >> -mrs x7, dbgbvr2_el1 >> -mrs x6, dbgbvr1_el1 >> -mrs x5, dbgbvr0_el1 >> - >> -adr x26, 1f >> -add x26, x26, x24, lsl #2 >> -br x26 >> - >> -1: >> -str x20, [x3, #(15 * 8)] >> -str x19, [x3, #(14 * 8)] >> -str x18, [x3, #(13 * 8)] >> -str x17, [x3, #(12 * 8)] >> -str x16, [x3, #(11 * 8)] >> -str x15, [x3, #(10 * 8)] >> -str x14, [x3, #(9 * 8)] >> -str x13, [x3, #(8 * 8)] >> -str x12, [x3, #(7 * 8)] >> -str x11, [x3, #(6 * 8)] >> -str x10, [x3, #(5 * 8)] >> -str x9, [x3, #(4 * 8)] >> -str x8, [x3, #(3 * 8)] &g
Re: [PATCH v6 09/12] KVM: arm64: introduce vcpu->arch.debug_ptr
Christoffer Dall writes: > On Fri, Jun 19, 2015 at 01:23:47PM +0100, Alex Bennée wrote: >> This introduces a level of indirection for the debug registers. Instead >> of using the sys_regs[] directly we store registers in a structure in >> the vcpu. As we are no longer tied to the layout of the sys_regs[] we >> can make the copies size appropriate for control and value registers. >> >> This also entails updating the sys_regs code to access this new >> structure. Instead of passing a register index we now pass an offset >> into the kvm_guest_debug_arch structure. >> >> We also need to ensure the GET/SET_ONE_REG ioctl operations store the >> registers in their correct location. >> >> Signed-off-by: Alex Bennée >> >> --- >> v6: >> - fix up some ws issues >> - correct clobber info >> - re-word commentary in kvm_host.h >> - fix endian access issues for aarch32 fields >> - revert all KVM_GET/SET_ONE_REG to 64bit (also see ABI update) >> --- >> >> +/* Used when AArch32 kernels trap to mapped debug registers */ >> +static inline bool trap_debug32(struct kvm_vcpu *vcpu, >> +const struct sys_reg_params *p, >> +const struct sys_reg_desc *rd) >> +{ >> +__u32 *r = (__u32 *) ((void * )&vcpu->arch.vcpu_debug_state + rd->reg); > > This still looks like something that's asking for BE trouble. Why not > access the register as a __u64 as it is and then only special-case it > somehow for the XVR thingy... Perhaps a separate function, see below. > >> +if (p->is_write) { >> +*r = *vcpu_reg(vcpu, p->Rt); >> +vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; >> +} else { >> +*vcpu_reg(vcpu, p->Rt) = *r; >> +} >> + >> +return true; >> +} >> + >> +static inline bool trap_debug64(struct kvm_vcpu *vcpu, >> +const struct sys_reg_params *p, >> +const struct sys_reg_desc *rd) >> +{ >> +__u64 *r = (__u64 *) ((void * )&vcpu->arch.vcpu_debug_state + rd->reg); >> +if (p->is_write) { >> +*r = *vcpu_reg(vcpu, p->Rt); >> +vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; >> +} else { >> +*vcpu_reg(vcpu, p->Rt) = *r; >> +} >> + >> +return true; >> +} >> + >> +static inline void reset_debug64(struct kvm_vcpu *vcpu, const struct >> sys_reg_desc *rd) >> +{ >> +__u64 *r = (__u64 *) ((void * )&vcpu->arch.vcpu_debug_state + rd->reg); >> +*r = rd->val; >> +} >> + >> static void reset_amair_el1(struct kvm_vcpu *vcpu, const struct >> sys_reg_desc *r) >> { >> u64 amair; >> @@ -240,16 +277,20 @@ static void reset_mpidr(struct kvm_vcpu *vcpu, const >> struct sys_reg_desc *r) >> #define DBG_BCR_BVR_WCR_WVR_EL1(n) \ >> /* DBGBVRn_EL1 */ \ >> { Op0(0b10), Op1(0b000), CRn(0b), CRm((n)), Op2(0b100), \ >> - trap_debug_regs, reset_val, (DBGBVR0_EL1 + (n)), 0 }, \ >> + trap_debug64, reset_debug64, \ >> + offsetof(struct kvm_guest_debug_arch, dbg_bvr[(n)]), 0 }, \ >> /* DBGBCRn_EL1 */ \ >> { Op0(0b10), Op1(0b000), CRn(0b), CRm((n)), Op2(0b101), \ >> - trap_debug_regs, reset_val, (DBGBCR0_EL1 + (n)), 0 }, \ >> + trap_debug64, reset_debug64, \ >> + offsetof(struct kvm_guest_debug_arch, dbg_bcr[(n)]), 0}, \ >> /* DBGWVRn_EL1 */ \ >> { Op0(0b10), Op1(0b000), CRn(0b), CRm((n)), Op2(0b110), \ >> - trap_debug_regs, reset_val, (DBGWVR0_EL1 + (n)), 0 }, \ >> + trap_debug64, reset_debug64, \ >> + offsetof(struct kvm_guest_debug_arch, dbg_wvr[(n)]), 0 }, \ >> /* DBGWCRn_EL1 */ \ >> { Op0(0b10), Op1(0b000), CRn(0b), CRm((n)), Op2(0b111), \ >> - trap_debug_regs, reset_val, (DBGWCR0_EL1 + (n)), 0 } >> + trap_debug64, reset_debug64, \ >> + offsetof(struct kvm_guest_debug_arch, dbg_wcr[(n)]), 0} >> >> /* >> * Architected system registers. >> @@ -502,42 +543,51 @@ static bool trap_dbgidr(s
[PATCH v6 11/12] KVM: arm64: enable KVM_CAP_SET_GUEST_DEBUG
Finally advertise the KVM capability for SET_GUEST_DEBUG. Once arm support is added this check can be moved to the common kvm_vm_ioctl_check_extension() code. Signed-off-by: Alex Bennée Acked-by: Christoffer Dall --- v3: - separated capability check from previous patches - moved into arm64 specific ioctl handler. v4: - add a-b-tag --- arch/arm64/kvm/reset.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index 21d5a62..88e5331 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -76,6 +76,9 @@ int kvm_arch_dev_ioctl_check_extension(long ext) case KVM_CAP_GUEST_DEBUG_HW_WPS: r = get_num_wrps(); break; + case KVM_CAP_SET_GUEST_DEBUG: + r = 1; + break; default: r = 0; } -- 2.4.3 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in Please read the FAQ at http://www.tux.org/lkml/
[PATCH v6 10/12] KVM: arm64: guest debug, HW assisted debug support
This adds support for userspace to control the HW debug registers for guest debug. In the debug ioctl we copy the IMPDEF defined number of registers into a new register set called host_debug_state. There is now a new vcpu parameter called debug_ptr which selects which register set is to copied into the real registers when world switch occurs. I've moved some helper functions into the hw_breakpoint.h header for re-use. As with single step we need to tweak the guest registers to enable the exceptions so we need to save and restore those bits. Two new capabilities have been added to the KVM_EXTENSION ioctl to allow userspace to query the number of hardware break and watch points available on the host hardware. Signed-off-by: Alex Bennée --- v2 - switched to C setup - replace host debug registers directly into context - minor tweak to api docs - setup right register for debug - add FAR_EL2 to debug exit structure - add support for trapping debug register access v3 - remove stray trace statement - fix spacing around operators (various) - clean-up usage of trap_debug - introduce debug_ptr, replace excessive memcpy stuff - don't use memcpy in ioctl, just assign - update cap ioctl documentation - reword a number comments - rename host_debug_state->external_debug_state v4 - use the new u32/u64 split debug_ptr approach - fix some wording/comments v5 - don't set MDSCR_EL1.KDE (not needed) v6 - update wording given change in commentary - KVM_GUESTDBG_USE_HW_BP->KVM_GUESTDBG_USE_HW --- Documentation/virtual/kvm/api.txt | 7 ++- arch/arm/kvm/arm.c | 7 +++ arch/arm64/include/asm/hw_breakpoint.h | 12 +++ arch/arm64/include/asm/kvm_host.h | 6 +- arch/arm64/kernel/hw_breakpoint.c | 12 --- arch/arm64/kvm/debug.c | 37 +- arch/arm64/kvm/handle_exit.c | 6 ++ arch/arm64/kvm/reset.c | 12 +++ include/uapi/linux/kvm.h | 2 ++ 9 files changed, 82 insertions(+), 19 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 33c8143..ada57df 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2668,7 +2668,7 @@ The top 16 bits of the control field are architecture specific control flags which can include the following: - KVM_GUESTDBG_USE_SW_BP: using software breakpoints [x86, arm64] - - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390] + - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390, arm64] - KVM_GUESTDBG_INJECT_DB: inject DB type exception [x86] - KVM_GUESTDBG_INJECT_BP: inject BP type exception [x86] - KVM_GUESTDBG_EXIT_PENDING: trigger an immediate guest exit [s390] @@ -2683,6 +2683,11 @@ updated to the correct (supplied) values. The second part of the structure is architecture specific and typically contains a set of debug registers. +For arm64 the number of debug registers is implementation defined and +can be determined by querying the KVM_CAP_GUEST_DEBUG_HW_BPS and +KVM_CAP_GUEST_DEBUG_HW_WPS capabilities which return a positive number +indicating the number of supported registers. + When debug events exit the main run loop with the reason KVM_EXIT_DEBUG with the kvm_debug_exit_arch part of the kvm_run structure containing architecture specific debug information. diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 0d17c7b..60c4045 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -307,6 +307,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) #define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE |\ KVM_GUESTDBG_USE_SW_BP | \ + KVM_GUESTDBG_USE_HW | \ KVM_GUESTDBG_SINGLESTEP) /** @@ -327,6 +328,12 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, if (dbg->control & KVM_GUESTDBG_ENABLE) { vcpu->guest_debug = dbg->control; + + /* Hardware assisted Break and Watch points */ + if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) { + vcpu->arch.external_debug_state = dbg->arch; + } + } else { /* If not enabled clear all flags */ vcpu->guest_debug = 0; diff --git a/arch/arm64/include/asm/hw_breakpoint.h b/arch/arm64/include/asm/hw_breakpoint.h index 52b484b..c450552 100644 --- a/arch/arm64/include/asm/hw_breakpoint.h +++ b/arch/arm64/include/asm/hw_breakpoint.h @@ -130,6 +130,18 @@ static inline void ptrace_hw_copy_thread(struct task_struct *task) } #endif +/* Determine number of BRP registers available. */ +static inline int get_num_brps(void) +{ + return ((read_cpuid(ID_AA64DFR0_EL1) >> 12) & 0xf) + 1; +} + +/* Determ
[PATCH v6 12/12] KVM: arm64: add trace points for guest_debug debug
This includes trace points for: kvm_arch_setup_guest_debug kvm_arch_clear_guest_debug I've also added some generic register setting trace events and also a trace point to dump the array of hardware registers. Signed-off-by: Alex Bennée --- v3 - add trace event for debug access. - remove short trace #define, rename trace events - use __print_array with fixed array instead of own func - rationalise trace points (only one per register changed) - add vcpu ptr to the debug_setup trace - remove :: in prints v4 - u32/u64 split on debug registers - fix for renames - add tracing of traps/set_guest_debug - remove handle_guest_debug trace v5 - minor print fmt fix - rm pstate traces v6 - fix merge conflicts - update control reg tracking to u64 (abi change) --- arch/arm/kvm/arm.c| 2 + arch/arm/kvm/trace.h | 17 arch/arm64/kvm/debug.c| 35 +++- arch/arm64/kvm/sys_regs.c | 10 + arch/arm64/kvm/trace.h| 105 ++ 5 files changed, 168 insertions(+), 1 deletion(-) diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 60c4045..d75c749 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -323,6 +323,8 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg) { + trace_kvm_set_guest_debug(vcpu, dbg->control); + if (dbg->control & ~KVM_GUESTDBG_VALID_MASK) return -EINVAL; diff --git a/arch/arm/kvm/trace.h b/arch/arm/kvm/trace.h index 0ec3539..3e346a6 100644 --- a/arch/arm/kvm/trace.h +++ b/arch/arm/kvm/trace.h @@ -317,6 +317,23 @@ TRACE_EVENT(kvm_toggle_cache, __entry->now ? "on" : "off") ); +TRACE_EVENT(kvm_set_guest_debug, + TP_PROTO(struct kvm_vcpu *vcpu, __u32 guest_debug), + TP_ARGS(vcpu, guest_debug), + + TP_STRUCT__entry( + __field(struct kvm_vcpu *, vcpu) + __field(__u32, guest_debug) + ), + + TP_fast_assign( + __entry->vcpu = vcpu; + __entry->guest_debug = guest_debug; + ), + + TP_printk("vcpu: %p, flags: 0x%08x", __entry->vcpu, __entry->guest_debug) +); + #endif /* _TRACE_KVM_H */ #undef TRACE_INCLUDE_PATH diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index b287bbc..f69570a 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -24,6 +24,8 @@ #include #include +#include "trace.h" + /* These are the bits of MDSCR_EL1 we may manipulate */ #define MDSCR_EL1_DEBUG_MASK (DBG_MDSCR_SS | \ DBG_MDSCR_KDE | \ @@ -44,11 +46,17 @@ static DEFINE_PER_CPU(u32, mdcr_el2); static void save_guest_debug_regs(struct kvm_vcpu *vcpu) { vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1); + + trace_kvm_arm_set_dreg32("Saved MDSCR_EL1", + vcpu->arch.guest_debug_preserved.mdscr_el1); } static void restore_guest_debug_regs(struct kvm_vcpu *vcpu) { vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1; + + trace_kvm_arm_set_dreg32("Restored MDSCR_EL1", + vcpu_sys_reg(vcpu, MDSCR_EL1)); } /** @@ -90,6 +98,8 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) { bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY); + trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug); + vcpu->arch.mdcr_el2 = __this_cpu_read(mdcr_el2) & MDCR_EL2_HPMN_MASK; vcpu->arch.mdcr_el2 |= (MDCR_EL2_TPM | MDCR_EL2_TPMCR | @@ -131,6 +141,8 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) vcpu_sys_reg(vcpu, MDSCR_EL1) &= ~DBG_MDSCR_SS; } + trace_kvm_arm_set_dreg32("SPSR_EL2", *vcpu_cpsr(vcpu)); + /* * HW Breakpoints and watchpoints * @@ -147,16 +159,29 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) vcpu->arch.debug_ptr = &vcpu->arch.external_debug_state; vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; trap_debug = true; + + trace_kvm_arm_set_regset("BKPTS", get_num_brps(), + &vcpu->arch.debug_ptr->dbg_bcr[0], + &vcpu->arch.debug_ptr->dbg_bvr[0]); + + trace_kvm_arm_set_regset("WAPTS", get_num_wrps(), + &vcpu->arch.debug_ptr->dbg_wcr[0], + &vcpu->arch.deb
[PATCH v6 03/12] KVM: arm64: guest debug, define API headers
This commit defines the API headers for guest debugging. There are two architecture specific debug structures: - kvm_guest_debug_arch, allows us to pass in HW debug registers - kvm_debug_exit_arch, signals exception and possible faulting address The type of debugging being used is controlled by the architecture specific control bits of the kvm_guest_debug->control flags in the ioctl structure. Signed-off-by: Alex Bennée Reviewed-by: David Hildenbrand Reviewed-by: Andrew Jones Acked-by: Christoffer Dall --- v2 - expose hsr and pc directly to user-space v3 - s/control/controlled/ in commit message - add v8 to ARM ARM comment (ARM Architecture Reference Manual) - add rb tag - rm pc, add far - re-word comments on alignment - rename KVM_ARM_NDBG_REGS -> KVM_ARM_MAX_DBG_REGS v4 - now uses common HW/SW BP define - add a-b-tag - use u32 for control regs v5 - revert to have arch specific KVM_GUESTDBG_USE_SW/HW_BP - rm stale comments dbgctrl was stored as u64 v6 - mv far comment from later patch - KVM_GUESTDBG_USE_HW_BP -> KVM_GUESTDBG_USE_HW - revert control regs to u64 (parity with GET/SET_ONE_REG) --- arch/arm64/include/uapi/asm/kvm.h | 27 +++ 1 file changed, 27 insertions(+) diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index d268320..d82f3f3 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -100,12 +100,39 @@ struct kvm_sregs { struct kvm_fpu { }; +/* + * See v8 ARM ARM D7.3: Debug Registers + * + * The architectural limit is 16 debug registers of each type although + * in practice there are usually less (see ID_AA64DFR0_EL1). + * + * Although the control registers are architecturally defined as 32 + * bits wide we use a 64 bit structure here to keep parity with + * KVM_GET/SET_ONE_REG behaviour which treats all system registers as + * 64 bit values. It also allows for the possibility of the + * architecture expanding the control registers without having to + * change the userspace ABI. + */ +#define KVM_ARM_MAX_DBG_REGS 16 struct kvm_guest_debug_arch { + __u64 dbg_bcr[KVM_ARM_MAX_DBG_REGS]; + __u64 dbg_bvr[KVM_ARM_MAX_DBG_REGS]; + __u64 dbg_wcr[KVM_ARM_MAX_DBG_REGS]; + __u64 dbg_wvr[KVM_ARM_MAX_DBG_REGS]; }; struct kvm_debug_exit_arch { + __u32 hsr; + __u64 far; /* used for watchpoints */ }; +/* + * Architecture specific defines for kvm_guest_debug->control + */ + +#define KVM_GUESTDBG_USE_SW_BP (1 << 16) +#define KVM_GUESTDBG_USE_HW(1 << 17) + struct kvm_sync_regs { }; -- 2.4.3 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in Please read the FAQ at http://www.tux.org/lkml/
[PATCH v6 06/12] KVM: arm64: guest debug, add SW break point support
This adds support for SW breakpoints inserted by userspace. We do this by trapping all guest software debug exceptions to the hypervisor (MDCR_EL2.TDE). The exit handler sets an exit reason of KVM_EXIT_DEBUG with the kvm_debug_exit_arch structure holding the exception syndrome information. It will be up to userspace to extract the PC (via GET_ONE_REG) and determine if the debug event was for a breakpoint it inserted. If not userspace will need to re-inject the correct exception restart the hypervisor to deliver the debug exception to the guest. Any other guest software debug exception (e.g. single step or HW assisted breakpoints) will cause an error and the VM to be killed. This is addressed by later patches which add support for the other debug types. Signed-off-by: Alex Bennée Reviewed-by: Christoffer Dall --- v2 - update to use new exit struct - tweak for C setup - do our setup in debug_setup/clear code - fixed up comments v3: - fix spacing in KVM_GUESTDBG_VALID_MASK - fix and clarify wording on kvm_handle_guest_debug - handle error case in kvm_handle_guest_debug - re-word the commit message v4 - rm else leg - add r-b-tag --- Documentation/virtual/kvm/api.txt | 2 +- arch/arm/kvm/arm.c| 2 +- arch/arm64/kvm/debug.c| 3 +++ arch/arm64/kvm/handle_exit.c | 36 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index ba635c7..33c8143 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2667,7 +2667,7 @@ when running. Common control bits are: The top 16 bits of the control field are architecture specific control flags which can include the following: - - KVM_GUESTDBG_USE_SW_BP: using software breakpoints [x86] + - KVM_GUESTDBG_USE_SW_BP: using software breakpoints [x86, arm64] - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390] - KVM_GUESTDBG_INJECT_DB: inject DB type exception [x86] - KVM_GUESTDBG_INJECT_BP: inject BP type exception [x86] diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 4a274e1..064c105 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -302,7 +302,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) kvm_arm_set_running_vcpu(NULL); } -#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE) +#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP) /** * kvm_arch_vcpu_ioctl_set_guest_debug - set up guest debugging diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index faf0e1f..8d1bfa4 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -73,6 +73,9 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) if (trap_debug) vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA; + /* Trap breakpoints? */ + if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) + vcpu->arch.mdcr_el2 |= MDCR_EL2_TDE; } void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 524fa25..27f38a9 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -82,6 +82,40 @@ static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run) return 1; } +/** + * kvm_handle_guest_debug - handle a debug exception instruction + * + * @vcpu: the vcpu pointer + * @run: access to the kvm_run structure for results + * + * We route all debug exceptions through the same handler. If both the + * guest and host are using the same debug facilities it will be up to + * userspace to re-inject the correct exception for guest delivery. + * + * @return: 0 (while setting run->exit_reason), -1 for error + */ +static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + u32 hsr = kvm_vcpu_get_hsr(vcpu); + int ret = 0; + + run->exit_reason = KVM_EXIT_DEBUG; + run->debug.arch.hsr = hsr; + + switch (hsr >> ESR_ELx_EC_SHIFT) { + case ESR_ELx_EC_BKPT32: + case ESR_ELx_EC_BRK64: + break; + default: + kvm_err("%s: un-handled case hsr: %#08x\n", + __func__, (unsigned int) hsr); + ret = -1; + break; + } + + return ret; +} + static exit_handle_fn arm_exit_handlers[] = { [ESR_ELx_EC_WFx]= kvm_handle_wfx, [ESR_ELx_EC_CP15_32]= kvm_handle_cp15_32, @@ -96,6 +130,8 @@ static exit_handle_fn arm_exit_handlers[] = { [ESR_ELx_EC_SYS64] = kvm_handle_sys_reg, [ESR_ELx_EC_IABT_LOW] = kvm_handle_guest_abort, [ESR_ELx_EC_DABT_LOW] = kvm_handle_guest_abort, + [ESR_ELx_EC_BKPT32] = kvm_handle_guest_debug, + [ESR_ELx_EC_BRK64] = kvm_handle_guest_debug, }; static exit_handle_fn kvm_get_exit_handler(s
[PATCH v6 01/12] KVM: add comments for kvm_debug_exit_arch struct
Bring into line with the comments for the other structures and their KVM_EXIT_* cases. Also update api.txt to reflect use in kvm_run documentation. Signed-off-by: Alex Bennée Reviewed-by: David Hildenbrand Reviewed-by: Andrew Jones Acked-by: Christoffer Dall --- v2 - add comments for other exit types v3 - s/commentary/comments/ - add rb tags - update api.txt kvm_run to include KVM_EXIT_DEBUG desc v4 - sp fixes - add a-b --- Documentation/virtual/kvm/api.txt | 4 +++- include/uapi/linux/kvm.h | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 9fa2bf8..c34c32d 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -3070,11 +3070,13 @@ data_offset describes where the data is located (KVM_EXIT_IO_OUT) or where kvm expects application code to place the data for the next KVM_RUN invocation (KVM_EXIT_IO_IN). Data format is a packed array. + /* KVM_EXIT_DEBUG */ struct { struct kvm_debug_exit_arch arch; } debug; -Unused. +If the exit_reason is KVM_EXIT_DEBUG, then a vcpu is processing a debug event +for which architecture specific information is returned. /* KVM_EXIT_MMIO */ struct { diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 4b60056..70ac641 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -237,6 +237,7 @@ struct kvm_run { __u32 count; __u64 data_offset; /* relative to kvm_run start */ } io; + /* KVM_EXIT_DEBUG */ struct { struct kvm_debug_exit_arch arch; } debug; @@ -285,6 +286,7 @@ struct kvm_run { __u32 data; __u8 is_write; } dcr; + /* KVM_EXIT_INTERNAL_ERROR */ struct { __u32 suberror; /* Available with KVM_CAP_INTERNAL_ERROR_DATA: */ @@ -295,6 +297,7 @@ struct kvm_run { struct { __u64 gprs[32]; } osi; + /* KVM_EXIT_PAPR_HCALL */ struct { __u64 nr; __u64 ret; -- 2.4.3 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in Please read the FAQ at http://www.tux.org/lkml/
[PATCH v6 08/12] KVM: arm64: re-factor hyp.S debug register code
This is a pre-cursor to sharing the code with the guest debug support. This replaces the big macro that fishes data out of a fixed location with a more general helper macro to restore a set of debug registers. It uses macro substitution so it can be re-used for debug control and value registers. It does however rely on the debug registers being 64 bit aligned (as they happen to be in the hyp ABI). Signed-off-by: Alex Bennée --- v3: - return to the patch series - add save and restore targets - change register use and document v4: - keep original setup/restore names - don't use split u32/u64 structure yet v6: - fix ws and clobber info in hyp.S --- arch/arm64/kvm/hyp.S | 517 ++- 1 file changed, 138 insertions(+), 379 deletions(-) diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S index 74e63d8..ee7f649 100644 --- a/arch/arm64/kvm/hyp.S +++ b/arch/arm64/kvm/hyp.S @@ -228,199 +228,52 @@ stp x24, x25, [x3, #160] .endm -.macro save_debug - // x2: base address for cpu context - // x3: tmp register - - mrs x26, id_aa64dfr0_el1 - ubfxx24, x26, #12, #4 // Extract BRPs - ubfxx25, x26, #20, #4 // Extract WRPs - mov w26, #15 - sub w24, w26, w24 // How many BPs to skip - sub w25, w26, w25 // How many WPs to skip - - add x3, x2, #CPU_SYSREG_OFFSET(DBGBCR0_EL1) - - adr x26, 1f - add x26, x26, x24, lsl #2 - br x26 -1: - mrs x20, dbgbcr15_el1 - mrs x19, dbgbcr14_el1 - mrs x18, dbgbcr13_el1 - mrs x17, dbgbcr12_el1 - mrs x16, dbgbcr11_el1 - mrs x15, dbgbcr10_el1 - mrs x14, dbgbcr9_el1 - mrs x13, dbgbcr8_el1 - mrs x12, dbgbcr7_el1 - mrs x11, dbgbcr6_el1 - mrs x10, dbgbcr5_el1 - mrs x9, dbgbcr4_el1 - mrs x8, dbgbcr3_el1 - mrs x7, dbgbcr2_el1 - mrs x6, dbgbcr1_el1 - mrs x5, dbgbcr0_el1 - - adr x26, 1f - add x26, x26, x24, lsl #2 - br x26 - -1: - str x20, [x3, #(15 * 8)] - str x19, [x3, #(14 * 8)] - str x18, [x3, #(13 * 8)] - str x17, [x3, #(12 * 8)] - str x16, [x3, #(11 * 8)] - str x15, [x3, #(10 * 8)] - str x14, [x3, #(9 * 8)] - str x13, [x3, #(8 * 8)] - str x12, [x3, #(7 * 8)] - str x11, [x3, #(6 * 8)] - str x10, [x3, #(5 * 8)] - str x9, [x3, #(4 * 8)] - str x8, [x3, #(3 * 8)] - str x7, [x3, #(2 * 8)] - str x6, [x3, #(1 * 8)] - str x5, [x3, #(0 * 8)] - - add x3, x2, #CPU_SYSREG_OFFSET(DBGBVR0_EL1) - - adr x26, 1f - add x26, x26, x24, lsl #2 - br x26 -1: - mrs x20, dbgbvr15_el1 - mrs x19, dbgbvr14_el1 - mrs x18, dbgbvr13_el1 - mrs x17, dbgbvr12_el1 - mrs x16, dbgbvr11_el1 - mrs x15, dbgbvr10_el1 - mrs x14, dbgbvr9_el1 - mrs x13, dbgbvr8_el1 - mrs x12, dbgbvr7_el1 - mrs x11, dbgbvr6_el1 - mrs x10, dbgbvr5_el1 - mrs x9, dbgbvr4_el1 - mrs x8, dbgbvr3_el1 - mrs x7, dbgbvr2_el1 - mrs x6, dbgbvr1_el1 - mrs x5, dbgbvr0_el1 - - adr x26, 1f - add x26, x26, x24, lsl #2 - br x26 - -1: - str x20, [x3, #(15 * 8)] - str x19, [x3, #(14 * 8)] - str x18, [x3, #(13 * 8)] - str x17, [x3, #(12 * 8)] - str x16, [x3, #(11 * 8)] - str x15, [x3, #(10 * 8)] - str x14, [x3, #(9 * 8)] - str x13, [x3, #(8 * 8)] - str x12, [x3, #(7 * 8)] - str x11, [x3, #(6 * 8)] - str x10, [x3, #(5 * 8)] - str x9, [x3, #(4 * 8)] - str x8, [x3, #(3 * 8)] - str x7, [x3, #(2 * 8)] - str x6, [x3, #(1 * 8)] - str x5, [x3, #(0 * 8)] - - add x3, x2, #CPU_SYSREG_OFFSET(DBGWCR0_EL1) - - adr x26, 1f - add x26, x26, x25, lsl #2 - br x26 +.macro save_debug type + // x4: pointer to register set + // x5: number of registers to skip + // x6..x22 trashed + + adr x22, 1f + add x22, x22, x5, lsl #2 + br x22 1: - mrs x20, dbgwcr15_el1 - mrs x19, dbgwcr14_el1 - mrs x18, dbgwcr13_el1 - mrs x17, dbgwcr12_el1 - mrs x16, dbgwcr11_el1 - mrs x15, dbgwcr10_el1 - mrs x14, dbgwcr9_el1 - mrs x13, dbgwcr8_el1 - mrs x12, dbgwcr7_el1 - mrs x11, dbgwcr6_el1 - mrs x10, dbgwcr5_el1 - mrs x9, dbgwcr4_el1 - mrs x8, dbgwcr3_el1 - mrs x7, dbgwcr2_el1 - mrs x6, dbgwcr1_el1 - mrs x5, dbgwcr0_el1 - -
[PATCH v6 05/12] KVM: arm: introduce kvm_arm_init/setup/clear_debug
This is a precursor for later patches which will need to do more to setup debug state before entering the hyp.S switch code. The existing functionality for setting mdcr_el2 has been moved out of hyp.S and now uses the value kept in vcpu->arch.mdcr_el2. As the assembler used to previously mask and preserve MDCR_EL2.HPMN I've had to add a mechanism to save the value of mdcr_el2 as a per-cpu variable during the initialisation code. The kernel never sets this number so we are assuming the bootcode has set up the correct value here. This also moves the conditional setting of the TDA bit from the hyp code into the C code which is currently used for the lazy debug register context switch code. Signed-off-by: Alex Bennée Reviewed-by: Christoffer Dall --- v3 - rename fns from arch->arm - preserve MDCR_EL2.HPMN setting - re-word some of the comments - fix some minor grammar nits - merge setting of mdcr_el2 - introduce trap_debug flag - move setup/clear within the irq lock section v4 - fix TDOSA desc - rm un-needed else leg - s/arch/arm/ v6 - add s-o-b tag --- arch/arm/include/asm/kvm_host.h | 4 ++ arch/arm/kvm/arm.c| 9 - arch/arm64/include/asm/kvm_asm.h | 2 + arch/arm64/include/asm/kvm_host.h | 5 +++ arch/arm64/kernel/asm-offsets.c | 1 + arch/arm64/kvm/Makefile | 2 +- arch/arm64/kvm/debug.c| 81 +++ arch/arm64/kvm/hyp.S | 19 - 8 files changed, 110 insertions(+), 13 deletions(-) create mode 100644 arch/arm64/kvm/debug.c diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index d71607c..746c0c69 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -236,4 +236,8 @@ 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) {} +static inline void kvm_arm_init_debug(void) {} +static inline void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) {} +static inline void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) {} + #endif /* __ARM_KVM_HOST_H__ */ diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 52a1d4d38..4a274e1 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -570,6 +570,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) continue; } + kvm_arm_setup_debug(vcpu); + /** * Enter the guest */ @@ -582,7 +584,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) vcpu->mode = OUTSIDE_GUEST_MODE; kvm_guest_exit(); trace_kvm_exit(kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu)); - /* + + kvm_arm_clear_debug(vcpu); + +/* * We may have taken a host interrupt in HYP mode (ie * while executing the guest). This interrupt is still * pending, as we haven't serviced it yet! @@ -930,6 +935,8 @@ static void cpu_init_hyp_mode(void *dummy) vector_ptr = (unsigned long)__kvm_hyp_vector; __cpu_init_hyp_mode(boot_pgd_ptr, pgd_ptr, hyp_stack_ptr, vector_ptr); + + kvm_arm_init_debug(); } static int hyp_init_cpu_notify(struct notifier_block *self, diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index 4f7310f..d6b507e 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -137,6 +137,8 @@ extern char __restore_vgic_v2_state[]; extern char __save_vgic_v3_state[]; extern char __restore_vgic_v3_state[]; +extern u32 __kvm_get_mdcr_el2(void); + #endif #endif /* __ARM_KVM_ASM_H__ */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index f0f58c9..7cb99b5 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -103,6 +103,7 @@ struct kvm_vcpu_arch { /* HYP configuration */ u64 hcr_el2; + u32 mdcr_el2; /* Exception Information */ struct kvm_vcpu_fault_info fault; @@ -250,4 +251,8 @@ 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) {} +void kvm_arm_init_debug(void); +void kvm_arm_setup_debug(struct kvm_vcpu *vcpu); +void kvm_arm_clear_debug(struct kvm_vcpu *vcpu); + #endif /* __ARM64_KVM_HOST_H__ */ diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index da675cc..dfb25a2 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -117,6 +117,7 @@ int main(void) DEFINE(VCPU_HPFAR_EL2, offsetof(struct kvm_vcpu, a
[PATCH v6 04/12] KVM: arm: guest debug, add stub KVM_SET_GUEST_DEBUG ioctl
This commit adds a stub function to support the KVM_SET_GUEST_DEBUG ioctl. Any unsupported flag will return -EINVAL. For now, only KVM_GUESTDBG_ENABLE is supported, although it won't have any effects. Signed-off-by: Alex Bennée . Reviewed-by: Christoffer Dall --- v2 - simplified form of the ioctl (stuff will go into setup_debug) v3 - KVM_GUESTDBG_VALID->KVM_GUESTDBG_VALID_MASK - move mask check to the top of function - add ioctl doc header - split capability into separate patch - tweaked commit wording w.r.t return of -EINVAL v4 - add r-b-tag --- Documentation/virtual/kvm/api.txt | 2 +- arch/arm/kvm/arm.c| 23 ++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index c34c32d..ba635c7 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2645,7 +2645,7 @@ handled. 4.87 KVM_SET_GUEST_DEBUG Capability: KVM_CAP_SET_GUEST_DEBUG -Architectures: x86, s390, ppc +Architectures: x86, s390, ppc, arm64 Type: vcpu ioctl Parameters: struct kvm_guest_debug (in) Returns: 0 on success; -1 on error diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index d9631ec..52a1d4d38 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -302,10 +302,31 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) kvm_arm_set_running_vcpu(NULL); } +#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE) + +/** + * kvm_arch_vcpu_ioctl_set_guest_debug - set up guest debugging + * @kvm: pointer to the KVM struct + * @kvm_guest_debug: the ioctl data buffer + * + * This sets up and enables the VM for guest debugging. Userspace + * passes in a control flag to enable different debug types and + * potentially other architecture specific information in the rest of + * the structure. + */ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg) { - return -EINVAL; + if (dbg->control & ~KVM_GUESTDBG_VALID_MASK) + return -EINVAL; + + if (dbg->control & KVM_GUESTDBG_ENABLE) { + vcpu->guest_debug = dbg->control; + } else { + /* If not enabled clear all flags */ + vcpu->guest_debug = 0; + } + return 0; } -- 2.4.3 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in Please read the FAQ at http://www.tux.org/lkml/
[PATCH v6 09/12] KVM: arm64: introduce vcpu->arch.debug_ptr
This introduces a level of indirection for the debug registers. Instead of using the sys_regs[] directly we store registers in a structure in the vcpu. As we are no longer tied to the layout of the sys_regs[] we can make the copies size appropriate for control and value registers. This also entails updating the sys_regs code to access this new structure. Instead of passing a register index we now pass an offset into the kvm_guest_debug_arch structure. We also need to ensure the GET/SET_ONE_REG ioctl operations store the registers in their correct location. Signed-off-by: Alex Bennée --- v6: - fix up some ws issues - correct clobber info - re-word commentary in kvm_host.h - fix endian access issues for aarch32 fields - revert all KVM_GET/SET_ONE_REG to 64bit (also see ABI update) --- arch/arm/kvm/arm.c| 3 + arch/arm64/include/asm/kvm_asm.h | 24 +++ arch/arm64/include/asm/kvm_host.h | 16 - arch/arm64/kernel/asm-offsets.c | 6 ++ arch/arm64/kvm/hyp.S | 24 --- arch/arm64/kvm/sys_regs.c | 148 +- 6 files changed, 161 insertions(+), 60 deletions(-) diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 9b3ed6d..0d17c7b 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -279,6 +279,9 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) /* Set up the timer */ kvm_timer_vcpu_init(vcpu); + /* Set the debug registers to be the guests */ + vcpu->arch.debug_ptr = &vcpu->arch.vcpu_debug_state; + return 0; } diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index d6b507e..e997404 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -46,24 +46,16 @@ #defineCNTKCTL_EL1 20 /* Timer Control Register (EL1) */ #definePAR_EL1 21 /* Physical Address Register */ #define MDSCR_EL1 22 /* Monitor Debug System Control Register */ -#define DBGBCR0_EL123 /* Debug Breakpoint Control Registers (0-15) */ -#define DBGBCR15_EL1 38 -#define DBGBVR0_EL139 /* Debug Breakpoint Value Registers (0-15) */ -#define DBGBVR15_EL1 54 -#define DBGWCR0_EL155 /* Debug Watchpoint Control Registers (0-15) */ -#define DBGWCR15_EL1 70 -#define DBGWVR0_EL171 /* Debug Watchpoint Value Registers (0-15) */ -#define DBGWVR15_EL1 86 -#define MDCCINT_EL187 /* Monitor Debug Comms Channel Interrupt Enable Reg */ +#define MDCCINT_EL123 /* Monitor Debug Comms Channel Interrupt Enable Reg */ /* 32bit specific registers. Keep them at the end of the range */ -#defineDACR32_EL2 88 /* Domain Access Control Register */ -#defineIFSR32_EL2 89 /* Instruction Fault Status Register */ -#defineFPEXC32_EL2 90 /* Floating-Point Exception Control Register */ -#defineDBGVCR32_EL291 /* Debug Vector Catch Register */ -#defineTEECR32_EL1 92 /* ThumbEE Configuration Register */ -#defineTEEHBR32_EL193 /* ThumbEE Handler Base Register */ -#defineNR_SYS_REGS 94 +#defineDACR32_EL2 24 /* Domain Access Control Register */ +#defineIFSR32_EL2 25 /* Instruction Fault Status Register */ +#defineFPEXC32_EL2 26 /* Floating-Point Exception Control Register */ +#defineDBGVCR32_EL227 /* Debug Vector Catch Register */ +#defineTEECR32_EL1 28 /* ThumbEE Configuration Register */ +#defineTEEHBR32_EL129 /* ThumbEE Handler Base Register */ +#defineNR_SYS_REGS 30 /* 32bit mapping */ #define c0_MPIDR (MPIDR_EL1 * 2) /* MultiProcessor ID Register */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index e2db6a6..9697daf 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -108,11 +108,25 @@ struct kvm_vcpu_arch { /* Exception Information */ struct kvm_vcpu_fault_info fault; - /* Debug state */ + /* Guest debug state */ u64 debug_flags; + /* +* We maintain more than a single set of debug registers to support +* debugging the guest from the host and to maintain separate host and +* guest state during world switches. vcpu_debug_state are the debug +* registers of the vcpu as the guest sees them. host_debug_state are +* the host registers which are saved and restored during world switches. +* +* debug_ptr points to the set of debug registers that should be loaded +* onto the hardware when running the guest. +*/ + struct kvm_guest_debug_arch *debug_ptr; + struct kvm_guest_debug_arch vcpu_debug_state; + /* Pointer to host CPU context */ kvm_cpu_context_t *host_cpu_context; + struct kvm_guest_
[PATCH v6 07/12] KVM: arm64: guest debug, add support for single-step
This adds support for single-stepping the guest. To do this we need to manipulate the guests PSTATE.SS and MDSCR_EL1.SS bits to trigger stepping. We take care to preserve MDSCR_EL1 and trap access to it to ensure we don't affect the apparent state of the guest. As we have to enable trapping of all software debug exceptions we suppress the ability of the guest to single-step itself. If we didn't we would have to deal with the exception arriving while the guest was in kernelspace when the guest is expecting to single-step userspace. This is something we don't want to unwind in the kernel. Once the host is no longer debugging the guest its ability to single-step userspace is restored. Signed-off-by: Alex Bennée Reviewed-by: Christoffer Dall --- v2 - Move pstate/mdscr manipulation into C - don't export guest_debug to assembly - add accessor for saved_debug regs - tweak save/restore of mdscr_el1 v3 - don't save PC in debug information struct - rename debug_saved_regs->guest_debug_state - save whole value, only use bits in restore - add save/restore_guest-debug_regs helper functions - simplify commit message for clarity - rm vcpu_debug_saved_reg access fn v4 - added more comments based on suggestions - guest_debug_state->guest_debug_preserved - no point masking restore, we will trap out v5 - more comments - don't bother preserving pstate.ss (guest never sees change) v6 - reword comments on guest SS suppression - simplify comment for save regs, SS explained in detail later on - add r-b-t (code) - expanded commit description --- arch/arm/kvm/arm.c| 4 ++- arch/arm64/include/asm/kvm_host.h | 11 +++ arch/arm64/kvm/debug.c| 68 --- arch/arm64/kvm/handle_exit.c | 2 ++ 4 files changed, 80 insertions(+), 5 deletions(-) diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 064c105..9b3ed6d 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -302,7 +302,9 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) kvm_arm_set_running_vcpu(NULL); } -#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP) +#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE |\ + KVM_GUESTDBG_USE_SW_BP | \ + KVM_GUESTDBG_SINGLESTEP) /** * kvm_arch_vcpu_ioctl_set_guest_debug - set up guest debugging diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 7cb99b5..e2db6a6 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -123,6 +123,17 @@ struct kvm_vcpu_arch { * here. */ + /* +* Guest registers we preserve during guest debugging. +* +* These shadow registers are updated by the kvm_handle_sys_reg +* trap handler if the guest accesses or updates them while we +* are using guest debug. +*/ + struct { + u32 mdscr_el1; + } guest_debug_preserved; + /* Don't run the guest */ bool pause; diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index 8d1bfa4..d439eb8 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -19,11 +19,39 @@ #include +#include +#include #include +#include + +/* These are the bits of MDSCR_EL1 we may manipulate */ +#define MDSCR_EL1_DEBUG_MASK (DBG_MDSCR_SS | \ + DBG_MDSCR_KDE | \ + DBG_MDSCR_MDE) static DEFINE_PER_CPU(u32, mdcr_el2); /** + * save/restore_guest_debug_regs + * + * For some debug operations we need to tweak some guest registers. As + * a result we need to save the state of those registers before we + * make those modifications. + * + * Guest access to MDSCR_EL1 is trapped by the hypervisor and handled + * after we have restored the preserved value to the main context. + */ +static void save_guest_debug_regs(struct kvm_vcpu *vcpu) +{ + vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1); +} + +static void restore_guest_debug_regs(struct kvm_vcpu *vcpu) +{ + vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1; +} + +/** * kvm_arm_init_debug - grab what we need for debug * * Currently the sole task of this function is to retrieve the initial @@ -38,7 +66,6 @@ void kvm_arm_init_debug(void) __this_cpu_write(mdcr_el2, kvm_call_hyp(__kvm_get_mdcr_el2)); } - /** * kvm_arm_setup_debug - set up debug related stuff * @@ -73,12 +100,45 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) if (trap_debug) vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA; - /* Trap breakpoints? */ - if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) + /* Is Guest debugging in effect? */ + if (vcpu->guest_debug) { + /* Route all software de
[PATCH v6 02/12] KVM: arm64: fix misleading comments in save/restore
The elr_el2 and spsr_el2 registers in fact contain the processor state before entry into the hypervisor code. In the case of guest state it could be in either el0 or el1. Signed-off-by: Alex Bennée --- arch/arm64/kvm/hyp.S | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S index 5befd01..cb9bdd8 100644 --- a/arch/arm64/kvm/hyp.S +++ b/arch/arm64/kvm/hyp.S @@ -50,8 +50,8 @@ stp x29, lr, [x3, #80] mrs x19, sp_el0 - mrs x20, elr_el2// EL1 PC - mrs x21, spsr_el2 // EL1 pstate + mrs x20, elr_el2// PC before hyp entry + mrs x21, spsr_el2 // pstate before hyp entry stp x19, x20, [x3, #96] str x21, [x3, #112] @@ -82,8 +82,8 @@ ldr x21, [x3, #16] msr sp_el0, x19 - msr elr_el2, x20// EL1 PC - msr spsr_el2, x21 // EL1 pstate + msr elr_el2, x20// PC to restore + msr spsr_el2, x21 // pstate to restore add x3, x2, #CPU_XREG_OFFSET(19) ldp x19, x20, [x3] -- 2.4.3 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 001/003] Attempt to cope with device changes and delayed kobject deallocation
Richard Watts writes: > Expose kobject_get_unless_zero() which will shortly be > needed by get_device_parent(). > > Signed-off-by: Richard Watts > --- > include/linux/kobject.h | 1 + > lib/kobject.c | 2 +- > 2 files changed, 2 insertions(+), 1 deletion(-) > > diff --git a/include/linux/kobject.h b/include/linux/kobject.h > index 2d61b90..662b136 100644 > --- a/include/linux/kobject.h > +++ b/include/linux/kobject.h > @@ -107,6 +107,7 @@ extern int __must_check kobject_rename(struct > kobject *, const char *new_name); > extern int __must_check kobject_move(struct kobject *, struct kobject *); > > extern struct kobject *kobject_get(struct kobject *kobj); > +extern struct kobject * __must_check kobject_get_unless_zero(struct > kobject *kobj); > extern void kobject_put(struct kobject *kobj); > > extern const void *kobject_namespace(struct kobject *kobj); > diff --git a/lib/kobject.c b/lib/kobject.c > index 3b841b9..3ba1db4 100644 > --- a/lib/kobject.c > +++ b/lib/kobject.c > @@ -586,7 +586,7 @@ struct kobject *kobject_get(struct kobject *kobj) > return kobj; > } > > -static struct kobject * __must_check kobject_get_unless_zero(struct > kobject *kobj) > +struct kobject * __must_check kobject_get_unless_zero(struct kobject *kobj) > { > if (!kref_get_unless_zero(&kobj->kref)) > kobj = NULL; Hi Richard, checkpatch is complaining about some trailing whitespace in this patch. > -- > 1.9.1 -- Alex Bennée -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v5 03/12] KVM: arm64: guest debug, define API headers
Christoffer Dall writes: > On Fri, May 29, 2015 at 10:30:19AM +0100, Alex Bennée wrote: >> This commit defines the API headers for guest debugging. There are two >> architecture specific debug structures: >> >> - kvm_guest_debug_arch, allows us to pass in HW debug registers >> - kvm_debug_exit_arch, signals exception and possible faulting address >> >> The type of debugging being used is controlled by the architecture >> specific control bits of the kvm_guest_debug->control flags in the ioctl >> structure. >> >> Signed-off-by: Alex Bennée >> Reviewed-by: David Hildenbrand >> Reviewed-by: Andrew Jones >> Acked-by: Christoffer Dall > > I can re-confirm my ack despite the changes in v4, but this really is > borderline to keep exiting r-b and a-b tags around from previous patches > I would think, but ok. I was wondering how much a patch has to change for the r-b tags to become invalid. The meat of the API hasn't changed much though. Drew/David, Are you still happy with this patch? > > -Christoffer > >> >> --- >> v2 >>- expose hsr and pc directly to user-space >> v3 >>- s/control/controlled/ in commit message >>- add v8 to ARM ARM comment (ARM Architecture Reference Manual) >>- add rb tag >>- rm pc, add far >>- re-word comments on alignment >>- rename KVM_ARM_NDBG_REGS -> KVM_ARM_MAX_DBG_REGS >> v4 >>- now uses common HW/SW BP define >>- add a-b-tag >>- use u32 for control regs >> v5 >>- revert to have arch specific KVM_GUESTDBG_USE_SW/HW_BP >>- rm stale comments dbgctrl was stored as u64 >> --- >> arch/arm64/include/uapi/asm/kvm.h | 20 >> 1 file changed, 20 insertions(+) >> >> diff --git a/arch/arm64/include/uapi/asm/kvm.h >> b/arch/arm64/include/uapi/asm/kvm.h >> index d268320..43758e7 100644 >> --- a/arch/arm64/include/uapi/asm/kvm.h >> +++ b/arch/arm64/include/uapi/asm/kvm.h >> @@ -100,12 +100,32 @@ struct kvm_sregs { >> struct kvm_fpu { >> }; >> >> +/* >> + * See v8 ARM ARM D7.3: Debug Registers >> + * >> + * The architectural limit is 16 debug registers of each type although >> + * in practice there are usually less (see ID_AA64DFR0_EL1). >> + */ >> +#define KVM_ARM_MAX_DBG_REGS 16 >> struct kvm_guest_debug_arch { >> +__u32 dbg_bcr[KVM_ARM_MAX_DBG_REGS]; >> +__u64 dbg_bvr[KVM_ARM_MAX_DBG_REGS]; >> +__u32 dbg_wcr[KVM_ARM_MAX_DBG_REGS]; >> +__u64 dbg_wvr[KVM_ARM_MAX_DBG_REGS]; >> }; >> >> struct kvm_debug_exit_arch { >> +__u32 hsr; >> +__u64 far; >> }; >> >> +/* >> + * Architecture specific defines for kvm_guest_debug->control >> + */ >> + >> +#define KVM_GUESTDBG_USE_SW_BP (1 << 16) >> +#define KVM_GUESTDBG_USE_HW_BP (1 << 17) >> + >> struct kvm_sync_regs { >> }; >> >> -- >> 2.4.1 >> -- Alex Bennée -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v5 07/12] KVM: arm64: guest debug, add support for single-step
Christoffer Dall writes: > On Fri, May 29, 2015 at 10:30:23AM +0100, Alex Bennée wrote: >> This adds support for single-stepping the guest. To do this we need to >> manipulate the guests PSTATE.SS and MDSCR_EL1.SS bits which we do in the >> kvm_arm_setup/clear_debug() so we don't affect the apparent state of the >> guest. Additionally while the host is debugging the guest we suppress >> the ability of the guest to single-step itself. > > I feel like there should be a slightly more elaborate explanation of > exactly what works and what doesn't work when the guest is single > stepping something and which choices we've made for supporting or not > supporting this. OK, I shall put bit more explanation. I was trying to avoid too much exposition in the commit comments vs the code. > >> >> Signed-off-by: Alex Bennée >> >> --- >> v2 >> - Move pstate/mdscr manipulation into C >> - don't export guest_debug to assembly >> - add accessor for saved_debug regs >> - tweak save/restore of mdscr_el1 >> v3 >> - don't save PC in debug information struct >> - rename debug_saved_regs->guest_debug_state >> - save whole value, only use bits in restore >> - add save/restore_guest-debug_regs helper functions >> - simplify commit message for clarity >> - rm vcpu_debug_saved_reg access fn >> v4 >> - added more comments based on suggestions >> - guest_debug_state->guest_debug_preserved >> - no point masking restore, we will trap out >> v5 >> - more comments >> - don't bother preserving pstate.ss > > it would have been good if there was some comment explaining the reason > for this change. > >> --- >> arch/arm/kvm/arm.c| 4 ++- >> arch/arm64/include/asm/kvm_host.h | 11 >> arch/arm64/kvm/debug.c| 58 >> --- >> arch/arm64/kvm/handle_exit.c | 2 ++ >> 4 files changed, 70 insertions(+), 5 deletions(-) >> >> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c >> index 064c105..9b3ed6d 100644 >> --- a/arch/arm/kvm/arm.c >> +++ b/arch/arm/kvm/arm.c >> @@ -302,7 +302,9 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) >> kvm_arm_set_running_vcpu(NULL); >> } >> >> -#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | >> KVM_GUESTDBG_USE_SW_BP) >> +#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE |\ >> +KVM_GUESTDBG_USE_SW_BP | \ >> +KVM_GUESTDBG_SINGLESTEP) >> >> /** >> * kvm_arch_vcpu_ioctl_set_guest_debug - set up guest debugging >> diff --git a/arch/arm64/include/asm/kvm_host.h >> b/arch/arm64/include/asm/kvm_host.h >> index 7cb99b5..e2db6a6 100644 >> --- a/arch/arm64/include/asm/kvm_host.h >> +++ b/arch/arm64/include/asm/kvm_host.h >> @@ -123,6 +123,17 @@ struct kvm_vcpu_arch { >> * here. >> */ >> >> +/* >> + * Guest registers we preserve during guest debugging. >> + * >> + * These shadow registers are updated by the kvm_handle_sys_reg >> + * trap handler if the guest accesses or updates them while we >> + * are using guest debug. >> + */ >> +struct { >> +u32 mdscr_el1; >> +} guest_debug_preserved; >> + >> /* Don't run the guest */ >> bool pause; >> >> diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c >> index 8d1bfa4..10a6baa 100644 >> --- a/arch/arm64/kvm/debug.c >> +++ b/arch/arm64/kvm/debug.c >> @@ -19,11 +19,41 @@ >> >> #include >> >> +#include >> +#include >> #include >> +#include >> + >> +/* These are the bits of MDSCR_EL1 we may manipulate */ >> +#define MDSCR_EL1_DEBUG_MASK(DBG_MDSCR_SS | \ >> +DBG_MDSCR_KDE | \ >> +DBG_MDSCR_MDE) >> >> static DEFINE_PER_CPU(u32, mdcr_el2); >> >> /** >> + * save/restore_guest_debug_regs >> + * >> + * For some debug operations we need to tweak some guest registers. As >> + * a result we need to save the state of those registers before we >> + * make those modifications. This does get confused if the guest >> + * attempts to control single step while being debugged. It will start >> + * working again once it is no longer being debugged by the host. > > What gets confused and what starts working? Maybe I should cut from "This does get..." and pu
[PATCH v2] KVM: arm64: fix misleading comments in save/restore
The elr_el2 and spsr_el2 registers in fact contain the processor state before entry into EL2. In the case of guest state it could be in either el0 or el1. Signed-off-by: Alex Bennée --- v2 - s/hypervisor code/EL2/ - comment: pc/pstate before entering/on return from el2 --- arch/arm64/kvm/hyp.S | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S index 5befd01..519805f 100644 --- a/arch/arm64/kvm/hyp.S +++ b/arch/arm64/kvm/hyp.S @@ -50,8 +50,8 @@ stp x29, lr, [x3, #80] mrs x19, sp_el0 - mrs x20, elr_el2// EL1 PC - mrs x21, spsr_el2 // EL1 pstate + mrs x20, elr_el2// pc before entering el2 + mrs x21, spsr_el2 // pstate before entering el2 stp x19, x20, [x3, #96] str x21, [x3, #112] @@ -82,8 +82,8 @@ ldr x21, [x3, #16] msr sp_el0, x19 - msr elr_el2, x20// EL1 PC - msr spsr_el2, x21 // EL1 pstate + msr elr_el2, x20// pc on return from el2 + msr spsr_el2, x21 // pstate on return from el2 add x3, x2, #CPU_XREG_OFFSET(19) ldp x19, x20, [x3] -- 2.4.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH] KVM: arm64: fix misleading comments in save/restore
Marc Zyngier writes: > On 04/06/15 11:20, Alex Bennée wrote: >> >> Marc Zyngier writes: >> >>> On 04/06/15 10:34, Christoffer Dall wrote: >>>> On Thu, May 28, 2015 at 10:43:06AM +0100, Alex Bennée wrote: >>>>> The elr_el2 and spsr_el2 registers in fact contain the processor state >>>>> before entry into the hypervisor code. >>>> >>>> be careful with your use of the hypervisor, in the KVM design the >>>> hypervisor is split across EL1 and EL2. >> >> "before entry into EL2." >> >>>> >>>>> In the case of guest state it >>>>> could be in either el0 or el1. >>>> >>>> true >>>> >>>>> >>>>> Signed-off-by: Alex Bennée >>>>> --- >>>>> arch/arm64/kvm/hyp.S | 8 >>>>> 1 file changed, 4 insertions(+), 4 deletions(-) >>>>> >>>>> diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S >>>>> index d755922..1940a4c 100644 >>>>> --- a/arch/arm64/kvm/hyp.S >>>>> +++ b/arch/arm64/kvm/hyp.S >>>>> @@ -50,8 +50,8 @@ >>>>> stp x29, lr, [x3, #80] >>>>> >>>>> mrs x19, sp_el0 >>>>> - mrs x20, elr_el2// EL1 PC >>>>> - mrs x21, spsr_el2 // EL1 pstate >>>>> + mrs x20, elr_el2// PC before hyp entry >>>>> + mrs x21, spsr_el2 // pstate before hyp entry >>>>> >>>>> stp x19, x20, [x3, #96] >>>>> str x21, [x3, #112] >>>>> @@ -82,8 +82,8 @@ >>>>> ldr x21, [x3, #16] >>>>> >>>>> msr sp_el0, x19 >>>>> - msr elr_el2, x20// EL1 PC >>>>> - msr spsr_el2, x21 // EL1 pstate >>>>> + msr elr_el2, x20// PC to restore >>>>> + msr spsr_el2, x21 // pstate to restore >>>> >>>> I don't feel like 'to restore' is much more meaningful here. >>>> >>>> I would actually vote for removin the comments all together, since one >>>> should really understand the code as opposed to the comments when >>>> reading this kind of stuff. >>>> >>>> Meh, I'm not sure. Your patch is definitely better than doing nothing. >>>> >>>> Marc? >>> >>> While I definitely agree that people should pay more attention to the >>> code rather than blindly trusting comments, I still think there is some >>> value in disambiguating the exception entry/return, because this bit of >>> code assumes some intimate knowledge of the ARMv8 exception model. >>> >>> As for the comments themselves, I'd rather have some wording that >>> clearly indicate that we're dealing with guest information, i.e: >>> >>> mrs x20, elr_el2// Guest PC >>> mrs x21, spsr_el2 // Guest pstate >>> >>> (and the same for the exception return). The "before hyp entry" and "to >>> restore" are not really useful (all the registers we are >>> saving/restoring fall into these categories). What I wanted to convey >>> here was that despite using an EL2 register, we are dealing with guest >>> registers. >> >> Which would be great it we were. However the code is used to >> save/restore the host context as well as the guest context hence my >> weasely words. > > Gahhh. You're right. I'm spending too much time on the VHE code these > days. Guess I'll stick to the weasel words then. Can you respin it with > Christoffer's comment addressed? Sure. Do you want it separated from the guest debug series or will you be happy to take it with it when ready? > > Thanks, > > M. -- Alex Bennée -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v5 08/12] KVM: arm64: re-factor hyp.S debug register code
Christoffer Dall writes: > On Fri, May 29, 2015 at 10:30:24AM +0100, Alex Bennée wrote: >> This is a pre-cursor to sharing the code with the guest debug support. >> This replaces the big macro that fishes data out of a fixed location >> with a more general helper macro to restore a set of debug registers. It >> uses macro substitution so it can be re-used for debug control and value >> registers. It does however rely on the debug registers being 64 bit >> aligned (as they happen to be in the hyp ABI). Oops I'd better fix that commit comment. >> >> Signed-off-by: Alex Bennée >> >> --- >> v3: >> - return to the patch series >> - add save and restore targets >> - change register use and document >> v4: >> - keep original setup/restore names >> - don't use split u32/u64 structure yet >> --- >> arch/arm64/kvm/hyp.S | 519 >> ++- >> 1 file changed, 140 insertions(+), 379 deletions(-) >> >> diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S >> index 74e63d8..9c4897d 100644 >> --- a/arch/arm64/kvm/hyp.S >> +++ b/arch/arm64/kvm/hyp.S > > > [...] > >> @@ -465,195 +318,52 @@ >> msr mdscr_el1, x25 >> .endm >> >> -.macro restore_debug >> -// x2: base address for cpu context >> -// x3: tmp register >> - >> -mrs x26, id_aa64dfr0_el1 >> -ubfxx24, x26, #12, #4 // Extract BRPs >> -ubfxx25, x26, #20, #4 // Extract WRPs >> -mov w26, #15 >> -sub w24, w26, w24 // How many BPs to skip >> -sub w25, w26, w25 // How many WPs to skip >> - >> -add x3, x2, #CPU_SYSREG_OFFSET(DBGBCR0_EL1) >> +.macro restore_debug type >> +// x4: pointer to register set >> +// x5: number of registers to skip > > nit: use tabs instead of spaces here... > >> +// x6..x22 trashed >> > > [...] > >> @@ -887,12 +597,63 @@ __restore_sysregs: >> restore_sysregs >> ret >> >> +/* Save debug state */ >> __save_debug: >> -save_debug >> +// x0: base address for vcpu context >> +// x2: ptr to current CPU context >> +// x4/x5: trashed > > I had a bunch of questions here which I think you missed last time > around: > 1. why do we need the vcpu context? We don't, I'll drop that > 2. what does 'current' mean here? Either the host or vcpu context depending which way we are currently going. > 3. you're also trashing everything that save_debug trashes, so x4/5, > x6-x22 trashed would be more correct OK > >> + >> +mrs x26, id_aa64dfr0_el1 >> +ubfxx24, x26, #12, #4 // Extract BRPs >> +ubfxx25, x26, #20, #4 // Extract WRPs >> +mov w26, #15 >> +sub w24, w26, w24 // How many BPs to skip >> +sub w25, w26, w25 // How many WPs to skip >> + >> +mov x5, x24 >> +add x4, x2, #CPU_SYSREG_OFFSET(DBGBCR0_EL1) >> +save_debug dbgbcr >> +add x4, x2, #CPU_SYSREG_OFFSET(DBGBVR0_EL1) >> +save_debug dbgbvr >> + >> +mov x5, x25 >> +add x4, x2, #CPU_SYSREG_OFFSET(DBGWCR0_EL1) >> +save_debug dbgwcr >> +add x4, x2, #CPU_SYSREG_OFFSET(DBGWVR0_EL1) >> +save_debug dbgwvr >> + >> +mrs x21, mdccint_el1 >> +str x21, [x2, #CPU_SYSREG_OFFSET(MDCCINT_EL1)] >> ret >> >> +/* Restore debug state */ >> __restore_debug: >> -restore_debug >> +// x0: base address for cpu context >> +// x2: ptr to current CPU context >> +// x4/x5: trashed > > and you missed these comments too, basically same stuff, but why was it > 'cpu' here and not 'vcpu' like above? Again we use the functions both for restoring host and vcpu debug context. > > note again, that you're explicitly touching x24, xx25, and x26 here as > well, so shouldn't they be listed as trashed? > >> + >> +mrs x26, id_aa64dfr0_el1 >> +ubfxx24, x26, #12, #4 // Extract BRPs >> +ubfxx25, x26, #20, #4 // Extract WRPs >> +mov w26, #15 >> + sub w24, w26, w24 // How many BPs to skip >> +sub w25, w26, w25 // How many WPs to skip >> + >> +mov x5, x24 >> +add x4, x2, #CPU_SYSREG_OFFSET(DBGBCR0_EL1) >> +restore_debug dbgbcr >> +add x4, x2, #CPU_SYSREG_OFFSET(DBGBVR0_EL1) >> +restore_debug dbgbvr >> + >> +mov x5, x25 >> +add x4, x2, #CPU_SYSREG_OFFSET(DBGWCR0_EL1) >> +restore_debug dbgwcr >> +add x4, x2, #CPU_SYSREG_OFFSET(DBGWVR0_EL1) >> +restore_debug dbgwvr >> + >> +ldr x21, [x2, #CPU_SYSREG_OFFSET(MDCCINT_EL1)] >> +msr mdccint_el1, x21 >> + >> ret >> >> __save_fpsimd: > > Thanks, > -Christoffer -- Alex Bennée -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/