The PIO scratch buffer is larger than a single page, and therefore
it is not possible to copy it in a single step to vcpu->arch/pio_data.
Bound each call to emulator_pio_in/out to a single page; keep
track of how many I/O operations are left in vcpu->arch.sev_pio_count,
so that the operation can be restarted in the complete_userspace_io
callback.
For OUT, this means that the previous kvm_sev_es_outs implementation
becomes an iterator of the loop, and we can consume the sev_pio_data
buffer before leaving to userspace.
For IN, instead, consuming the buffer and decreasing sev_pio_count
is always done in the complete_userspace_io callback, because that
is when the memcpy is done into sev_pio_data.
Cc: stable(a)vger.kernel.org
Fixes: 7ed9abfe8e9f ("KVM: SVM: Support string IO operations for an SEV-ES guest")
Reported-by: Felix Wilhelm <fwilhelm(a)google.com>
Reviewed-by: Maxim Levitsky <mlevitsk(a)redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini(a)redhat.com>
---
arch/x86/include/asm/kvm_host.h | 1 +
arch/x86/kvm/x86.c | 72 +++++++++++++++++++++++++--------
2 files changed, 57 insertions(+), 16 deletions(-)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 6bed6c416c6c..5a0298aa56ba 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -703,6 +703,7 @@ struct kvm_vcpu_arch {
struct kvm_pio_request pio;
void *pio_data;
void *sev_pio_data;
+ unsigned sev_pio_count;
u8 event_exit_inst_len;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 23e772412134..b26647a5ea22 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -12386,38 +12386,77 @@ int kvm_sev_es_mmio_read(struct kvm_vcpu *vcpu, gpa_t gpa, unsigned int bytes,
EXPORT_SYMBOL_GPL(kvm_sev_es_mmio_read);
static int kvm_sev_es_outs(struct kvm_vcpu *vcpu, unsigned int size,
- unsigned int port, unsigned int count)
+ unsigned int port);
+
+static int complete_sev_es_emulated_outs(struct kvm_vcpu *vcpu)
{
- int ret = emulator_pio_out(vcpu, size, port,
- vcpu->arch.sev_pio_data, count);
+ int size = vcpu->arch.pio.size;
+ int port = vcpu->arch.pio.port;
+
+ vcpu->arch.pio.count = 0;
+ if (vcpu->arch.sev_pio_count)
+ return kvm_sev_es_outs(vcpu, size, port);
+ return 1;
+}
+
+static int kvm_sev_es_outs(struct kvm_vcpu *vcpu, unsigned int size,
+ unsigned int port)
+{
+ for (;;) {
+ unsigned int count =
+ min_t(unsigned int, PAGE_SIZE / size, vcpu->arch.sev_pio_count);
+ int ret = emulator_pio_out(vcpu, size, port, vcpu->arch.sev_pio_data, count);
+
+ /* memcpy done already by emulator_pio_out. */
+ vcpu->arch.sev_pio_count -= count;
+ vcpu->arch.sev_pio_data += count * vcpu->arch.pio.size;
+ if (!ret)
+ break;
- if (ret) {
/* Emulation done by the kernel. */
- return ret;
+ if (!vcpu->arch.sev_pio_count)
+ return 1;
}
- vcpu->arch.pio.count = 0;
+ vcpu->arch.complete_userspace_io = complete_sev_es_emulated_outs;
return 0;
}
+static int kvm_sev_es_ins(struct kvm_vcpu *vcpu, unsigned int size,
+ unsigned int port);
+
+static void advance_sev_es_emulated_ins(struct kvm_vcpu *vcpu)
+{
+ unsigned count = vcpu->arch.pio.count;
+ complete_emulator_pio_in(vcpu, vcpu->arch.sev_pio_data);
+ vcpu->arch.sev_pio_count -= count;
+ vcpu->arch.sev_pio_data += count * vcpu->arch.pio.size;
+}
+
static int complete_sev_es_emulated_ins(struct kvm_vcpu *vcpu)
{
- memcpy(vcpu->arch.sev_pio_data, vcpu->arch.pio_data,
- vcpu->arch.pio.count * vcpu->arch.pio.size);
- vcpu->arch.pio.count = 0;
+ int size = vcpu->arch.pio.size;
+ int port = vcpu->arch.pio.port;
+ advance_sev_es_emulated_ins(vcpu);
+ if (vcpu->arch.sev_pio_count)
+ return kvm_sev_es_ins(vcpu, size, port);
return 1;
}
static int kvm_sev_es_ins(struct kvm_vcpu *vcpu, unsigned int size,
- unsigned int port, unsigned int count)
+ unsigned int port)
{
- int ret = emulator_pio_in(vcpu, size, port,
- vcpu->arch.sev_pio_data, count);
+ for (;;) {
+ unsigned int count =
+ min_t(unsigned int, PAGE_SIZE / size, vcpu->arch.sev_pio_count);
+ if (!__emulator_pio_in(vcpu, size, port, count))
+ break;
- if (ret) {
/* Emulation done by the kernel. */
- return ret;
+ advance_sev_es_emulated_ins(vcpu);
+ if (!vcpu->arch.sev_pio_count)
+ return 1;
}
vcpu->arch.complete_userspace_io = complete_sev_es_emulated_ins;
@@ -12429,8 +12468,9 @@ int kvm_sev_es_string_io(struct kvm_vcpu *vcpu, unsigned int size,
int in)
{
vcpu->arch.sev_pio_data = data;
- return in ? kvm_sev_es_ins(vcpu, size, port, count)
- : kvm_sev_es_outs(vcpu, size, port, count);
+ vcpu->arch.sev_pio_count = count;
+ return in ? kvm_sev_es_ins(vcpu, size, port)
+ : kvm_sev_es_outs(vcpu, size, port);
}
EXPORT_SYMBOL_GPL(kvm_sev_es_string_io);
--
2.27.0
emulator_pio_in handles both the case where the data is pending in
vcpu->arch.pio.count, and the case where I/O has to be done via either
an in-kernel device or a userspace exit. For SEV-ES we would like
to split these, to identify clearly the moment at which the
sev_pio_data is consumed. To this end, create two different
functions: __emulator_pio_in fills in vcpu->arch.pio.count, while
complete_emulator_pio_in clears it and releases vcpu->arch.pio.data.
Because this patch has to be backported, things are left a bit messy.
kernel_pio() operates on vcpu->arch.pio, which leads to emulator_pio_in()
having with two calls to complete_emulator_pio_in(). It will be fixed
in the next release.
While at it, remove the unused void* val argument of emulator_pio_in_out.
The function currently hardcodes vcpu->arch.pio_data as the
source/destination buffer, which sucks but will be fixed after the more
severe SEV-ES buffer overflow.
No functional change intended.
Cc: stable(a)vger.kernel.org
Fixes: 7ed9abfe8e9f ("KVM: SVM: Support string IO operations for an SEV-ES guest")
Signed-off-by: Paolo Bonzini <pbonzini(a)redhat.com>
---
arch/x86/kvm/x86.c | 45 ++++++++++++++++++++++++++++-----------------
1 file changed, 28 insertions(+), 17 deletions(-)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 78ed0fe9fa1e..c51ea81019e3 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -6906,7 +6906,7 @@ static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)
}
static int emulator_pio_in_out(struct kvm_vcpu *vcpu, int size,
- unsigned short port, void *val,
+ unsigned short port,
unsigned int count, bool in)
{
vcpu->arch.pio.port = port;
@@ -6927,26 +6927,38 @@ static int emulator_pio_in_out(struct kvm_vcpu *vcpu, int size,
return 0;
}
+static int __emulator_pio_in(struct kvm_vcpu *vcpu, int size,
+ unsigned short port, unsigned int count)
+{
+ WARN_ON(vcpu->arch.pio.count);
+ memset(vcpu->arch.pio_data, 0, size * count);
+ return emulator_pio_in_out(vcpu, size, port, count, true);
+}
+
+static void complete_emulator_pio_in(struct kvm_vcpu *vcpu, int size,
+ unsigned short port, void *val)
+{
+ memcpy(val, vcpu->arch.pio_data, size * vcpu->arch.pio.count);
+ trace_kvm_pio(KVM_PIO_IN, port, size, vcpu->arch.pio.count, vcpu->arch.pio_data);
+ vcpu->arch.pio.count = 0;
+}
+
static int emulator_pio_in(struct kvm_vcpu *vcpu, int size,
unsigned short port, void *val, unsigned int count)
{
- int ret;
+ if (vcpu->arch.pio.count) {
+ /* Complete previous iteration. */
+ } else {
+ int r = __emulator_pio_in(vcpu, size, port, count);
+ if (!r)
+ return r;
- if (vcpu->arch.pio.count)
- goto data_avail;
-
- memset(vcpu->arch.pio_data, 0, size * count);
-
- ret = emulator_pio_in_out(vcpu, size, port, val, count, true);
- if (ret) {
-data_avail:
- memcpy(val, vcpu->arch.pio_data, size * count);
- trace_kvm_pio(KVM_PIO_IN, port, size, count, vcpu->arch.pio_data);
- vcpu->arch.pio.count = 0;
- return 1;
+ /* Results already available, fall through. */
}
- return 0;
+ WARN_ON(count != vcpu->arch.pio.count);
+ complete_emulator_pio_in(vcpu, size, port, val);
+ return 1;
}
static int emulator_pio_in_emulated(struct x86_emulate_ctxt *ctxt,
@@ -6965,12 +6977,11 @@ static int emulator_pio_out(struct kvm_vcpu *vcpu, int size,
memcpy(vcpu->arch.pio_data, val, size * count);
trace_kvm_pio(KVM_PIO_OUT, port, size, count, vcpu->arch.pio_data);
- ret = emulator_pio_in_out(vcpu, size, port, (void *)val, count, false);
+ ret = emulator_pio_in_out(vcpu, size, port, count, false);
if (ret)
vcpu->arch.pio.count = 0;
return ret;
-
}
static int emulator_pio_out_emulated(struct x86_emulate_ctxt *ctxt,
--
2.27.0
A few very small cleanups to the functions, smushed together because
the patch is already very small like this:
- inline emulator_pio_in_emulated and emulator_pio_out_emulated,
since we already have the vCPU
- remove the data argument and pull setting vcpu->arch.sev_pio_data into
the caller
- remove unnecessary clearing of vcpu->arch.pio.count when
emulation is done by the kernel (and therefore vcpu->arch.pio.count
is already clear on exit from emulator_pio_in and emulator_pio_out).
No functional change intended.
Cc: stable(a)vger.kernel.org
Fixes: 7ed9abfe8e9f ("KVM: SVM: Support string IO operations for an SEV-ES guest")
Reviewed-by: Maxim Levitsky <mlevitsk(a)redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini(a)redhat.com>
---
arch/x86/kvm/x86.c | 31 +++++++++++++++----------------
1 file changed, 15 insertions(+), 16 deletions(-)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index dff28a4fbb21..78ed0fe9fa1e 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -12383,34 +12383,32 @@ static int complete_sev_es_emulated_ins(struct kvm_vcpu *vcpu)
}
static int kvm_sev_es_outs(struct kvm_vcpu *vcpu, unsigned int size,
- unsigned int port, void *data, unsigned int count)
+ unsigned int port, unsigned int count)
{
- int ret;
+ int ret = emulator_pio_out(vcpu, size, port,
+ vcpu->arch.sev_pio_data, count);
- ret = emulator_pio_out_emulated(vcpu->arch.emulate_ctxt, size, port,
- data, count);
- if (ret)
+ if (ret) {
+ /* Emulation done by the kernel. */
return ret;
+ }
vcpu->arch.pio.count = 0;
-
return 0;
}
static int kvm_sev_es_ins(struct kvm_vcpu *vcpu, unsigned int size,
- unsigned int port, void *data, unsigned int count)
+ unsigned int port, unsigned int count)
{
- int ret;
+ int ret = emulator_pio_in(vcpu, size, port,
+ vcpu->arch.sev_pio_data, count);
- ret = emulator_pio_in_emulated(vcpu->arch.emulate_ctxt, size, port,
- data, count);
if (ret) {
- vcpu->arch.pio.count = 0;
- } else {
- vcpu->arch.sev_pio_data = data;
- vcpu->arch.complete_userspace_io = complete_sev_es_emulated_ins;
+ /* Emulation done by the kernel. */
+ return ret;
}
+ vcpu->arch.complete_userspace_io = complete_sev_es_emulated_ins;
return 0;
}
@@ -12418,8 +12416,9 @@ int kvm_sev_es_string_io(struct kvm_vcpu *vcpu, unsigned int size,
unsigned int port, void *data, unsigned int count,
int in)
{
- return in ? kvm_sev_es_ins(vcpu, size, port, data, count)
- : kvm_sev_es_outs(vcpu, size, port, data, count);
+ vcpu->arch.sev_pio_data = data;
+ return in ? kvm_sev_es_ins(vcpu, size, port, count)
+ : kvm_sev_es_outs(vcpu, size, port, count);
}
EXPORT_SYMBOL_GPL(kvm_sev_es_string_io);
--
2.27.0
We will be using this field for OUTS emulation as well, in case the
data that is pushed via OUTS spans more than one page. In that case,
there will be a need to save the data pointer across exits to userspace.
So, change the name to something that refers to any kind of PIO.
Also spell out what it is used for, namely SEV-ES.
No functional change intended.
Cc: stable(a)vger.kernel.org
Fixes: 7ed9abfe8e9f ("KVM: SVM: Support string IO operations for an SEV-ES guest")
Reviewed-by: Maxim Levitsky <mlevitsk(a)redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini(a)redhat.com>
---
arch/x86/include/asm/kvm_host.h | 2 +-
arch/x86/kvm/x86.c | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index f8f48a7ec577..6bed6c416c6c 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -702,7 +702,7 @@ struct kvm_vcpu_arch {
struct kvm_pio_request pio;
void *pio_data;
- void *guest_ins_data;
+ void *sev_pio_data;
u8 event_exit_inst_len;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 381384a54790..379175b725a1 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -12370,7 +12370,7 @@ EXPORT_SYMBOL_GPL(kvm_sev_es_mmio_read);
static int complete_sev_es_emulated_ins(struct kvm_vcpu *vcpu)
{
- memcpy(vcpu->arch.guest_ins_data, vcpu->arch.pio_data,
+ memcpy(vcpu->arch.sev_pio_data, vcpu->arch.pio_data,
vcpu->arch.pio.count * vcpu->arch.pio.size);
vcpu->arch.pio.count = 0;
@@ -12402,7 +12402,7 @@ static int kvm_sev_es_ins(struct kvm_vcpu *vcpu, unsigned int size,
if (ret) {
vcpu->arch.pio.count = 0;
} else {
- vcpu->arch.guest_ins_data = data;
+ vcpu->arch.sev_pio_data = data;
vcpu->arch.complete_userspace_io = complete_sev_es_emulated_ins;
}
--
2.27.0
On Fri, Oct 22, 2021 at 12:43:33PM +0000, Aditya Garg wrote:
> I am really sorry. I don’t have any experience regarding submitting patches upstream. I copied and pasted the diff generated using git. My email client doesn’t seem to support git send email. I would be happy if I could get some guidance.
First and very important guidance: do not top-post!
Next, as Lee pointed out there are available documents on how to submit patches
properly. Please, read them (they are available inside kernel source tree as
well).
TL;DR: again as Lee said, `git format-patch` (produces a file in mbox format)
followed by `git send-email` will suffice.
> From: Lee Jones <lee.jones(a)linaro.org>
> Sent: Friday, October 22, 2021 1:28:42 PM
> To: Aditya Garg <gargaditya08(a)live.com>
> Cc: andriy.shevchenko(a)linux.intel.com <andriy.shevchenko(a)linux.intel.com>; stable(a)vger.kernel.org <stable(a)vger.kernel.org>; Orlando Chamberlain <redecorating(a)protonmail.com>
> Subject: Re: [PATCHv4] mfd: intel-lpss: Add support for MacBookPro16,2 ICL-N UART
>
> On Fri, 22 Oct 2021, Aditya Garg wrote:
>
> >
> > From 76d8253d90233b2c2d3fbc82355c603bf0eb9964 Mon Sep 17 00:00:00 2001
> > From: Orlando Chamberlain <redecorating(a)protonmail.com>
> > Date: Fri, 1 Oct 2021 13:30:19 +0530
> > Subject: [PATCH] Add support for MacBookPro16,2 UART
> > Cc: stable(a)vger.kernel.org
>
> What is this?
>
> These headers should not be part of the patch.
>
> How are you submitting this?
> What tools are you using?
> Did you read the documents I sent you (see below)?
>
> > Added 8086:38a8 to the intel_lpss_pci driver. It is an Intel Ice Lake PCH-N UART controller present on the MacBookPro16,2.
>
> This line is too long.
>
> > Signed-off-by: Aditya Garg <gargaditya08(a)live.com>
> > ---
> > drivers/mfd/intel-lpss-pci.c | 2 ++
> > 1 file changed, 2 insertions(+)
>
> This diff looks better.
>
> > diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c
> > index c54d19fb1..33d5043fd 100644
> > --- a/drivers/mfd/intel-lpss-pci.c
> > +++ b/drivers/mfd/intel-lpss-pci.c
> > @@ -253,6 +253,8 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
> > { PCI_VDEVICE(INTEL, 0x34ea), (kernel_ulong_t)&bxt_i2c_info },
> > { PCI_VDEVICE(INTEL, 0x34eb), (kernel_ulong_t)&bxt_i2c_info },
> > { PCI_VDEVICE(INTEL, 0x34fb), (kernel_ulong_t)&spt_info },
> > + /* ICL-N*/
> > + { PCI_VDEVICE(INTEL, 0x38a8), (kernel_ulong_t)&bxt_uart_info },
> > /* TGL-H */
> > { PCI_VDEVICE(INTEL, 0x43a7), (kernel_ulong_t)&bxt_uart_info },
> > { PCI_VDEVICE(INTEL, 0x43a8), (kernel_ulong_t)&bxt_uart_info },
> >
> > > On 21-Oct-2021, at 4:45 PM, Lee Jones <lee.jones(a)linaro.org> wrote:
> > >
> > > On Thu, 14 Oct 2021, andriy.shevchenko(a)linux.intel.com wrote:
> > >
> > >> On Thu, Oct 14, 2021 at 04:15:05AM +0000, Aditya Garg wrote:
> > >>
> > >> Entire message looks like a mess. Are you sure you are using proper tools
> > >> for sending it?
> > >
> > > Agreed.
> > >
> > > I can't apply this until it's submitted properly.
> > >
> > > - Please read Documentation/process/submitting-patches.rst
> > > - Please read Documentation/process/coding-style.rst
> > >
> > > If you have any questions, please reach out. We're happy to help.
> > >
>
> This quoted text can't be part of a submitted patch.
>
> Please submit the patch on its own, as a new thread, using the correct
> tooling (provided mostly by the Git package (i.e. `git format-patch`
> and `git send-email`).
>
> If you're stuck, or there is something you do not understand, please
> ask.
--
With Best Regards,
Andy Shevchenko
This is a note to let you know that I've just added the patch titled
usb: musb: Balance list entry in musb_gadget_queue
to my usb git tree which can be found at
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git
in the usb-testing branch.
The patch will show up in the next release of the linux-next tree
(usually sometime within the next 24 hours during the week.)
The patch will be merged to the usb-next branch sometime soon,
after it passes testing, and the merge window is open.
If you have any questions about this process, please let me know.
>From 21b5fcdccb32ff09b6b63d4a83c037150665a83f Mon Sep 17 00:00:00 2001
From: Viraj Shah <viraj.shah(a)linutronix.de>
Date: Thu, 21 Oct 2021 11:36:44 +0200
Subject: usb: musb: Balance list entry in musb_gadget_queue
musb_gadget_queue() adds the passed request to musb_ep::req_list. If the
endpoint is idle and it is the first request then it invokes
musb_queue_resume_work(). If the function returns an error then the
error is passed to the caller without any clean-up and the request
remains enqueued on the list. If the caller enqueues the request again
then the list corrupts.
Remove the request from the list on error.
Fixes: ea2f35c01d5ea ("usb: musb: Fix sleeping function called from invalid context for hdrc glue")
Cc: stable <stable(a)vger.kernel.org>
Signed-off-by: Viraj Shah <viraj.shah(a)linutronix.de>
Link: https://lore.kernel.org/r/20211021093644.4734-1-viraj.shah@linutronix.de
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
---
drivers/usb/musb/musb_gadget.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 98c0f4c1bffd..51274b87f46c 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -1247,9 +1247,11 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
status = musb_queue_resume_work(musb,
musb_ep_restart_resume_work,
request);
- if (status < 0)
+ if (status < 0) {
dev_err(musb->controller, "%s resume work: %i\n",
__func__, status);
+ list_del(&request->list);
+ }
}
unlock:
--
2.33.1