Date   

Re: [PATCH 1/2] HV: acrntrace: Output event time cost with milliseconds

Eddie Dong
 

Why we use float? Long should be enough, not?

-----Original Message-----
From: acrn-dev@...
[mailto:acrn-dev@...] On Behalf Of Kaige Fu
Sent: Tuesday, August 14, 2018 2:29 PM
To: acrn-dev@...
Cc: Yan, Like <like.yan@...>
Subject: [acrn-dev] [PATCH 1/2] HV: acrntrace: Output event time cost with
milliseconds

Originally, we output "Time Consumed" with RTC cycles. It's not easy to
read.
So, this patch convert it to milliseconds.

BTW, this patch also output "Total run time" with ms instead of original
second.

Signed-off-by: Kaige Fu <kaige.fu@...>
---
tools/acrntrace/scripts/vmexit_analyze.py | 30
+++++++++++++++++++-----------
1 file changed, 19 insertions(+), 11 deletions(-)

diff --git a/tools/acrntrace/scripts/vmexit_analyze.py
b/tools/acrntrace/scripts/vmexit_analyze.py
index 21cfa23..0eee590 100755
--- a/tools/acrntrace/scripts/vmexit_analyze.py
+++ b/tools/acrntrace/scripts/vmexit_analyze.py
@@ -80,7 +80,13 @@ TIME_IN_EXIT = {
# 4 * 64bit per trace entry
TRCREC = "QQQQ"

-def parse_trace_data(ifile):
+def tsc_to_ms(tsc, freq):
+ """convert tsc to milliseconds according freq
+ """
+
+ return float(tsc) / (float(freq) * 1000)
+
+def parse_trace_data(ifile, freq):
"""parse the trace data file
Args:
ifile: input trace data file
@@ -116,7 +122,8 @@ def parse_trace_data(ifile):
tsc_last_exit_period = tsc_enter - tsc_exit

if tsc_last_exit_period != 0:
- TIME_IN_EXIT[last_ev_id] += tsc_last_exit_period
+ TIME_IN_EXIT[last_ev_id] += \
+ tsc_to_ms(tsc_last_exit_period, freq)

elif event == VM_EXIT:
tsc_exit = tsc
@@ -157,30 +164,31 @@ def generate_report(ofile, freq):
tsc_end %d, tsc_begin %d"\
% (TSC_END, TSC_BEGIN)

- rt_sec = float(rt_cycle) / (float(freq) * 1000 * 1000)
+ rt_ms = tsc_to_ms(rt_cycle, freq)
+ rt_sec = float(rt_ms) / 1000.0

for event in LIST_EVENTS:
total_exit_time += TIME_IN_EXIT[event]

print ("Total run time: %d cycles" % (rt_cycle))
print ("TSC Freq: %f MHz" % (freq))
- print ("Total run time: %d sec" % (rt_sec))
+ print ("Total run time: %d ms" % (rt_ms))

- f_csv.writerow(['Run time(cycles)', 'Run time(Sec)',
'Freq(MHz)'])
+ f_csv.writerow(['Run time(cycles)', 'Run time(ms)',
+ 'Freq(MHz)'])
f_csv.writerow(['%d' % (rt_cycle),
- '%.3f' % (rt_sec),
+ '%.3f' % (rt_ms),
'%d' % (freq)])

- print ("Event \tNR_Exit \tNR_Exit/Sec \tTime Consumed
\tTime Percentage")
+ print ("Event \tNR_Exit \tNR_Exit/Sec \tTime Consumed(ms)
+ \tTime Percentage")
f_csv.writerow(['Exit_Reason',
'NR_Exit',
'NR_Exit/Sec',
- 'Time Consumed(cycles)',
+ 'Time Consumed(ms)',
'Time Percentage'])

for event in LIST_EVENTS:
ev_freq = float(NR_EXITS[event]) / rt_sec
- pct = float(TIME_IN_EXIT[event]) * 100 / float(rt_cycle)
+ pct = float(TIME_IN_EXIT[event]) * 100 / float(rt_ms)

print ("%s \t%d \t%.2f \t%d \t%2.2f" %
(event, NR_EXITS[event], ev_freq,
TIME_IN_EXIT[event], pct)) @@ -189,7 +197,7 @@ def
generate_report(ofile, freq):
f_csv.writerow(row)

ev_freq = float(TOTAL_NR_EXITS) / rt_sec
- pct = float(total_exit_time) * 100 / float(rt_cycle)
+ pct = float(total_exit_time) * 100 / float(rt_ms)
print("Total \t%d \t%.2f \t%d \t%2.2f"
% (TOTAL_NR_EXITS, ev_freq, total_exit_time, pct))
row = ["Total", TOTAL_NR_EXITS, '%.2f' % ev_freq,
total_exit_time, @@ -211,6 +219,6 @@ def analyze_vm_exit(ifile, ofile):
print("VM exits analysis started... \n\tinput file: %s\n"
"\toutput file: %s.csv" % (ifile, ofile))

- parse_trace_data(ifile)
+ parse_trace_data(ifile, TSC_FREQ)
# save report to the output file
generate_report(ofile, TSC_FREQ)
--
2.7.4



Re: [PATCH] VHM: add ioctl/hypercall for UOS intr data monitor

Minggui Cao
 

On 8/14/2018 2:56 PM, Zhao, Yakui wrote:

-----Original Message-----
From: acrn-dev@... [mailto:acrn-dev@...]
On Behalf Of Minggui Cao
Sent: Tuesday, August 14, 2018 2:17 PM
To: acrn-dev@...
Cc: Cao, Minggui <minggui.cao@...>
Subject: [acrn-dev] [PATCH] VHM: add ioctl/hypercall for UOS intr data
monitor

DM or VM monitor can use this ioctl/hypercall to get the UOS interrupt count
data, to check if it in normal status, and give a response.

Signed-off-by: Minggui Cao <minggui.cao@...>
---
drivers/char/vhm/vhm_dev.c | 17 +++++++++++++++++
drivers/vhm/vhm_hypercall.c | 5 +++++
include/linux/vhm/acrn_hv_defs.h | 1 +
include/linux/vhm/vhm_hypercall.h | 1 +
include/linux/vhm/vhm_ioctl_defs.h | 1 +
5 files changed, 25 insertions(+)

diff --git a/drivers/char/vhm/vhm_dev.c b/drivers/char/vhm/vhm_dev.c
index c681ace..fc1e852 100644
--- a/drivers/char/vhm/vhm_dev.c
+++ b/drivers/char/vhm/vhm_dev.c
@@ -604,6 +604,23 @@ static long vhm_dev_ioctl(struct file *filep,
break;
}

+ case IC_VM_INTR_MONITOR: {
+ struct page *page;
+
+ ret = get_user_pages_fast(ioctl_param, 1, 1, &page);
+ if (unlikely(ret != 1) || (page == NULL)) {
+ pr_err("vhm-dev: failed to pin intr hdr buffer!\n");
+ return -ENOMEM;
+ }
+
+ ret = hcall_vm_intr_monitor(vm->vmid, page_to_phys(page));
+ if (ret < 0) {
+ pr_err("vhm-dev: monitor intr data err=%d\n", ret);
+ return -EFAULT;
+ }
Does the page include intr data of monitored VM after this call is returned?
Yes, it includes the intr data.
Another is that since we are adding more and more hcall, can we add one HC to query whether one function is supported in HV?
In such case it can help to assure that the kernel is decoupled with HV.
if that we need add another one hypercall :); currently if not support, the HV will return failure; it should be OK.
actually, I have a re-factor idea on current hypercall, talked with Jason/Eddie, will give a proposal recently; mainly points:
is to classify them, if not need VHM handle, just pass it to HV.... (hypercall + sub-cmd) to design them; reduce some of them, just add in DM/HV.

+ break;
+ }
+
default:
pr_warn("Unknown IOCTL 0x%x\n", ioctl_num);
ret = 0;
diff --git a/drivers/vhm/vhm_hypercall.c b/drivers/vhm/vhm_hypercall.c
index 9a92d68..9a974e8 100644
--- a/drivers/vhm/vhm_hypercall.c
+++ b/drivers/vhm/vhm_hypercall.c
@@ -172,3 +172,8 @@ inline long hcall_vm_gpa2hpa(unsigned long vmid,
unsigned long addr) {
return acrn_hypercall2(HC_VM_GPA2HPA, vmid, addr); }
+
+inline long hcall_vm_intr_monitor(unsigned long vmid, unsigned long
+addr) {
+ return acrn_hypercall2(HC_VM_INTR_MONITOR, vmid, addr); }
diff --git a/include/linux/vhm/acrn_hv_defs.h
b/include/linux/vhm/acrn_hv_defs.h
index c12deaa..01494de 100644
--- a/include/linux/vhm/acrn_hv_defs.h
+++ b/include/linux/vhm/acrn_hv_defs.h
@@ -85,6 +85,7 @@
#define HC_DEASSERT_IRQLINE _HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x01)
#define HC_PULSE_IRQLINE _HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x02)
#define HC_INJECT_MSI _HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x03)
+#define HC_VM_INTR_MONITOR _HC_ID(HC_ID, HC_ID_IRQ_BASE +
0x04UL)

/* DM ioreq management */
#define HC_ID_IOREQ_BASE 0x30UL
diff --git a/include/linux/vhm/vhm_hypercall.h
b/include/linux/vhm/vhm_hypercall.h
index bc9feec..868541e 100644
--- a/include/linux/vhm/vhm_hypercall.h
+++ b/include/linux/vhm/vhm_hypercall.h
@@ -166,5 +166,6 @@ inline long hcall_reset_ptdev_intr_info(unsigned long
vmid,
unsigned long pt_irq);
inline long hcall_remap_pci_msix(unsigned long vmid, unsigned long msi);
inline long hcall_vm_gpa2hpa(unsigned long vmid, unsigned long addr);
+inline long hcall_vm_intr_monitor(unsigned long vmid, unsigned long
+addr);

#endif /* __VHM_HYPERCALL_H__ */
diff --git a/include/linux/vhm/vhm_ioctl_defs.h
b/include/linux/vhm/vhm_ioctl_defs.h
index 32e081a..042b8e9 100644
--- a/include/linux/vhm/vhm_ioctl_defs.h
+++ b/include/linux/vhm/vhm_ioctl_defs.h
@@ -80,6 +80,7 @@
#define IC_DEASSERT_IRQLINE _IC_ID(IC_ID, IC_ID_IRQ_BASE + 0x01)
#define IC_PULSE_IRQLINE _IC_ID(IC_ID, IC_ID_IRQ_BASE + 0x02)
#define IC_INJECT_MSI _IC_ID(IC_ID, IC_ID_IRQ_BASE + 0x03)
+#define IC_VM_INTR_MONITOR _IC_ID(IC_ID, IC_ID_IRQ_BASE + 0x04)

/* DM ioreq management */
#define IC_ID_IOREQ_BASE 0x30UL
--
2.7.4



Re: [PATCH] VHM: add ioctl/hypercall for UOS intr data monitor

Zhao, Yakui
 

-----Original Message-----
From: acrn-dev@... [mailto:acrn-dev@...]
On Behalf Of Minggui Cao
Sent: Tuesday, August 14, 2018 2:17 PM
To: acrn-dev@...
Cc: Cao, Minggui <minggui.cao@...>
Subject: [acrn-dev] [PATCH] VHM: add ioctl/hypercall for UOS intr data
monitor

DM or VM monitor can use this ioctl/hypercall to get the UOS interrupt count
data, to check if it in normal status, and give a response.

Signed-off-by: Minggui Cao <minggui.cao@...>
---
drivers/char/vhm/vhm_dev.c | 17 +++++++++++++++++
drivers/vhm/vhm_hypercall.c | 5 +++++
include/linux/vhm/acrn_hv_defs.h | 1 +
include/linux/vhm/vhm_hypercall.h | 1 +
include/linux/vhm/vhm_ioctl_defs.h | 1 +
5 files changed, 25 insertions(+)

diff --git a/drivers/char/vhm/vhm_dev.c b/drivers/char/vhm/vhm_dev.c
index c681ace..fc1e852 100644
--- a/drivers/char/vhm/vhm_dev.c
+++ b/drivers/char/vhm/vhm_dev.c
@@ -604,6 +604,23 @@ static long vhm_dev_ioctl(struct file *filep,
break;
}

+ case IC_VM_INTR_MONITOR: {
+ struct page *page;
+
+ ret = get_user_pages_fast(ioctl_param, 1, 1, &page);
+ if (unlikely(ret != 1) || (page == NULL)) {
+ pr_err("vhm-dev: failed to pin intr hdr buffer!\n");
+ return -ENOMEM;
+ }
+
+ ret = hcall_vm_intr_monitor(vm->vmid, page_to_phys(page));
+ if (ret < 0) {
+ pr_err("vhm-dev: monitor intr data err=%d\n", ret);
+ return -EFAULT;
+ }
Does the page include intr data of monitored VM after this call is returned?

Another is that since we are adding more and more hcall, can we add one HC to query whether one function is supported in HV?
In such case it can help to assure that the kernel is decoupled with HV.

+ break;
+ }
+
default:
pr_warn("Unknown IOCTL 0x%x\n", ioctl_num);
ret = 0;
diff --git a/drivers/vhm/vhm_hypercall.c b/drivers/vhm/vhm_hypercall.c
index 9a92d68..9a974e8 100644
--- a/drivers/vhm/vhm_hypercall.c
+++ b/drivers/vhm/vhm_hypercall.c
@@ -172,3 +172,8 @@ inline long hcall_vm_gpa2hpa(unsigned long vmid,
unsigned long addr) {
return acrn_hypercall2(HC_VM_GPA2HPA, vmid, addr); }
+
+inline long hcall_vm_intr_monitor(unsigned long vmid, unsigned long
+addr) {
+ return acrn_hypercall2(HC_VM_INTR_MONITOR, vmid, addr); }
diff --git a/include/linux/vhm/acrn_hv_defs.h
b/include/linux/vhm/acrn_hv_defs.h
index c12deaa..01494de 100644
--- a/include/linux/vhm/acrn_hv_defs.h
+++ b/include/linux/vhm/acrn_hv_defs.h
@@ -85,6 +85,7 @@
#define HC_DEASSERT_IRQLINE _HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x01)
#define HC_PULSE_IRQLINE _HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x02)
#define HC_INJECT_MSI _HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x03)
+#define HC_VM_INTR_MONITOR _HC_ID(HC_ID, HC_ID_IRQ_BASE +
0x04UL)

/* DM ioreq management */
#define HC_ID_IOREQ_BASE 0x30UL
diff --git a/include/linux/vhm/vhm_hypercall.h
b/include/linux/vhm/vhm_hypercall.h
index bc9feec..868541e 100644
--- a/include/linux/vhm/vhm_hypercall.h
+++ b/include/linux/vhm/vhm_hypercall.h
@@ -166,5 +166,6 @@ inline long hcall_reset_ptdev_intr_info(unsigned long
vmid,
unsigned long pt_irq);
inline long hcall_remap_pci_msix(unsigned long vmid, unsigned long msi);
inline long hcall_vm_gpa2hpa(unsigned long vmid, unsigned long addr);
+inline long hcall_vm_intr_monitor(unsigned long vmid, unsigned long
+addr);

#endif /* __VHM_HYPERCALL_H__ */
diff --git a/include/linux/vhm/vhm_ioctl_defs.h
b/include/linux/vhm/vhm_ioctl_defs.h
index 32e081a..042b8e9 100644
--- a/include/linux/vhm/vhm_ioctl_defs.h
+++ b/include/linux/vhm/vhm_ioctl_defs.h
@@ -80,6 +80,7 @@
#define IC_DEASSERT_IRQLINE _IC_ID(IC_ID, IC_ID_IRQ_BASE + 0x01)
#define IC_PULSE_IRQLINE _IC_ID(IC_ID, IC_ID_IRQ_BASE + 0x02)
#define IC_INJECT_MSI _IC_ID(IC_ID, IC_ID_IRQ_BASE + 0x03)
+#define IC_VM_INTR_MONITOR _IC_ID(IC_ID, IC_ID_IRQ_BASE + 0x04)

/* DM ioreq management */
#define IC_ID_IOREQ_BASE 0x30UL
--
2.7.4



[RESEND 1/2] tools: acrnalyze: Output event time cost with milliseconds

Kaige Fu
 

Originally, we output "Time Consumed" with RTC cycles. It's not easy to read.
So, this patch convert it to milliseconds.

BTW, this patch also output "Total run time" with ms instead of original second.

Signed-off-by: Kaige Fu <kaige.fu@...>
---
tools/acrntrace/scripts/vmexit_analyze.py | 30 +++++++++++++++++++-----------
1 file changed, 19 insertions(+), 11 deletions(-)

diff --git a/tools/acrntrace/scripts/vmexit_analyze.py b/tools/acrntrace/scripts/vmexit_analyze.py
index 21cfa23..0eee590 100755
--- a/tools/acrntrace/scripts/vmexit_analyze.py
+++ b/tools/acrntrace/scripts/vmexit_analyze.py
@@ -80,7 +80,13 @@ TIME_IN_EXIT = {
# 4 * 64bit per trace entry
TRCREC = "QQQQ"

-def parse_trace_data(ifile):
+def tsc_to_ms(tsc, freq):
+ """convert tsc to milliseconds according freq
+ """
+
+ return float(tsc) / (float(freq) * 1000)
+
+def parse_trace_data(ifile, freq):
"""parse the trace data file
Args:
ifile: input trace data file
@@ -116,7 +122,8 @@ def parse_trace_data(ifile):
tsc_last_exit_period = tsc_enter - tsc_exit

if tsc_last_exit_period != 0:
- TIME_IN_EXIT[last_ev_id] += tsc_last_exit_period
+ TIME_IN_EXIT[last_ev_id] += \
+ tsc_to_ms(tsc_last_exit_period, freq)

elif event == VM_EXIT:
tsc_exit = tsc
@@ -157,30 +164,31 @@ def generate_report(ofile, freq):
tsc_end %d, tsc_begin %d"\
% (TSC_END, TSC_BEGIN)

- rt_sec = float(rt_cycle) / (float(freq) * 1000 * 1000)
+ rt_ms = tsc_to_ms(rt_cycle, freq)
+ rt_sec = float(rt_ms) / 1000.0

for event in LIST_EVENTS:
total_exit_time += TIME_IN_EXIT[event]

print ("Total run time: %d cycles" % (rt_cycle))
print ("TSC Freq: %f MHz" % (freq))
- print ("Total run time: %d sec" % (rt_sec))
+ print ("Total run time: %d ms" % (rt_ms))

- f_csv.writerow(['Run time(cycles)', 'Run time(Sec)', 'Freq(MHz)'])
+ f_csv.writerow(['Run time(cycles)', 'Run time(ms)', 'Freq(MHz)'])
f_csv.writerow(['%d' % (rt_cycle),
- '%.3f' % (rt_sec),
+ '%.3f' % (rt_ms),
'%d' % (freq)])

- print ("Event \tNR_Exit \tNR_Exit/Sec \tTime Consumed \tTime Percentage")
+ print ("Event \tNR_Exit \tNR_Exit/Sec \tTime Consumed(ms) \tTime Percentage")
f_csv.writerow(['Exit_Reason',
'NR_Exit',
'NR_Exit/Sec',
- 'Time Consumed(cycles)',
+ 'Time Consumed(ms)',
'Time Percentage'])

for event in LIST_EVENTS:
ev_freq = float(NR_EXITS[event]) / rt_sec
- pct = float(TIME_IN_EXIT[event]) * 100 / float(rt_cycle)
+ pct = float(TIME_IN_EXIT[event]) * 100 / float(rt_ms)

print ("%s \t%d \t%.2f \t%d \t%2.2f" %
(event, NR_EXITS[event], ev_freq, TIME_IN_EXIT[event], pct))
@@ -189,7 +197,7 @@ def generate_report(ofile, freq):
f_csv.writerow(row)

ev_freq = float(TOTAL_NR_EXITS) / rt_sec
- pct = float(total_exit_time) * 100 / float(rt_cycle)
+ pct = float(total_exit_time) * 100 / float(rt_ms)
print("Total \t%d \t%.2f \t%d \t%2.2f"
% (TOTAL_NR_EXITS, ev_freq, total_exit_time, pct))
row = ["Total", TOTAL_NR_EXITS, '%.2f' % ev_freq, total_exit_time,
@@ -211,6 +219,6 @@ def analyze_vm_exit(ifile, ofile):
print("VM exits analysis started... \n\tinput file: %s\n"
"\toutput file: %s.csv" % (ifile, ofile))

- parse_trace_data(ifile)
+ parse_trace_data(ifile, TSC_FREQ)
# save report to the output file
generate_report(ofile, TSC_FREQ)
--
2.7.4


[RESEND 2/2] tools: acrnalyze: Make the result easier to read

Kaige Fu
 

Originally, we don't format the output of analyser well. It is hard to read the
result.

This patch make every entry of the result align with the corresponding title to
make it easier for users to read.

Without patch:
Event NR_Exit NR_Exit/Sec Time Consumed(ms) Time Percentage
VMEXIT_INTERRUPT_WINDOW 78090 130.15 40 0.01
VMEXIT_CR_ACCESS 0 0.00 0 0.00
VMEXIT_APICV_ACCESS 0 0.00 0 0.00
VMEXIT_EXCEPTION_OR_NMI 0 0.00 0 0.00
VMEXIT_RDTSC 0 0.00 0 0.00

...

Vector Count NR_Exit/Sec
0x000000f0 82337 137.23
0x000000ef 247713 412.85

With patch:
Event NR_Exit NR_Exit/Sec Time Consumed(ms) Time percentage
VMEXIT_INTERRUPT_WINDOW 78090 130.15 40 0.01
VMEXIT_WRMSR 309085 515.14 128 0.02
VMEXIT_RDTSCP 0 0.00 0 0.00
VMEXIT_IO_INSTRUCTION 75250 125.42 12924 2.15
VMEXIT_EXTERNAL_INTERRUPT 330050 550.08 726 0.12

...

Vector Count NR_Exit/Sec
0x000000f0 82337 137.23
0x000000ef 247713 412.85

Signed-off-by: Kaige Fu <kaige.fu@...>
---
tools/acrntrace/scripts/irq_analyze.py | 6 +++---
tools/acrntrace/scripts/vmexit_analyze.py | 9 +++++----
2 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/tools/acrntrace/scripts/irq_analyze.py b/tools/acrntrace/scripts/irq_analyze.py
index f475da7..0d555aa 100755
--- a/tools/acrntrace/scripts/irq_analyze.py
+++ b/tools/acrntrace/scripts/irq_analyze.py
@@ -80,12 +80,12 @@ def generate_report(ofile, freq):

rt_sec = float(rt_cycle) / (float(freq) * 1000 * 1000)

- print ("\nVector \t\tCount \tNR_Exit/Sec")
+ print ("%-8s\t%-8s\t%-8s" % ("Vector", "Count", "NR_Exit/Sec"))
f_csv.writerow(['Vector', 'NR_Exit', 'NR_Exit/Sec'])
for e in IRQ_EXITS.keys():
pct = float(IRQ_EXITS[e]) / rt_sec
- print ("0x%08x \t %d \t%.2f" % (e, IRQ_EXITS[e], pct))
- f_csv.writerow([e, IRQ_EXITS[e], '%.2f' % pct])
+ print ("0x%08x\t%-8d\t%-8.2f" % (e, IRQ_EXITS[e], pct))
+ f_csv.writerow(['0x%08x' % e, IRQ_EXITS[e], '%.2f' % pct])

except IOError as err:
print ("Output File Error: " + str(err))
diff --git a/tools/acrntrace/scripts/vmexit_analyze.py b/tools/acrntrace/scripts/vmexit_analyze.py
index 0eee590..96dd40a 100755
--- a/tools/acrntrace/scripts/vmexit_analyze.py
+++ b/tools/acrntrace/scripts/vmexit_analyze.py
@@ -179,7 +179,8 @@ def generate_report(ofile, freq):
'%.3f' % (rt_ms),
'%d' % (freq)])

- print ("Event \tNR_Exit \tNR_Exit/Sec \tTime Consumed(ms) \tTime Percentage")
+ print ("%-28s\t%-12s\t%-12s\t%-18s\t%-16s" % ("Event", "NR_Exit",
+ "NR_Exit/Sec", "Time Consumed(ms)", "Time percentage"))
f_csv.writerow(['Exit_Reason',
'NR_Exit',
'NR_Exit/Sec',
@@ -190,7 +191,7 @@ def generate_report(ofile, freq):
ev_freq = float(NR_EXITS[event]) / rt_sec
pct = float(TIME_IN_EXIT[event]) * 100 / float(rt_ms)

- print ("%s \t%d \t%.2f \t%d \t%2.2f" %
+ print ("%-28s\t%-12d\t%-12.2f\t%-18d\t%-16.2f" %
(event, NR_EXITS[event], ev_freq, TIME_IN_EXIT[event], pct))
row = [event, NR_EXITS[event], '%.2f' % ev_freq, TIME_IN_EXIT[event],
'%2.2f' % (pct)]
@@ -198,8 +199,8 @@ def generate_report(ofile, freq):

ev_freq = float(TOTAL_NR_EXITS) / rt_sec
pct = float(total_exit_time) * 100 / float(rt_ms)
- print("Total \t%d \t%.2f \t%d \t%2.2f"
- % (TOTAL_NR_EXITS, ev_freq, total_exit_time, pct))
+ print("%-28s\t%-12d\t%-12.2f\t%-18d\t%-16.2f"
+ % ("Total", TOTAL_NR_EXITS, ev_freq, total_exit_time, pct))
row = ["Total", TOTAL_NR_EXITS, '%.2f' % ev_freq, total_exit_time,
'%2.2f' % (pct)]
f_csv.writerow(row)
--
2.7.4


[RESEND 0/2] Minor improvement of acrnalyze

Kaige Fu
 

Kaige Fu (2):
tools: acrnalyze: Output event time cost with milliseconds
tools: acrnalyze: Make the result easier to read

tools/acrntrace/scripts/irq_analyze.py | 6 ++---
tools/acrntrace/scripts/vmexit_analyze.py | 37 +++++++++++++++++++------------
2 files changed, 26 insertions(+), 17 deletions(-)

--
2.7.4


Re: [PATCH 0/2] Minor improvement of acrnalyser

Kaige Fu
 

Patch title are wrong. Will fix it and resend them.
Sorry for the noise.

On 08-14 Tue 14:29, Kaige Fu wrote:
This patch mainly focus on:
- Output "Time Consumed" and "Total run time" with milliseconds.
- Format the output to make the result entry align with the title.

Kaige Fu (2):
HV: acrntrace: Output event time cost with milliseconds
HV: acrntrace: Make the result easier to read

tools/acrntrace/scripts/irq_analyze.py | 6 ++---
tools/acrntrace/scripts/vmexit_analyze.py | 37 +++++++++++++++++++------------
2 files changed, 26 insertions(+), 17 deletions(-)

--
2.7.4




[PATCH v5 1/1] vbs: fix virtio_vq_index_get func handling of multi VQ concurrent request.

Ong Hock Yu <ong.hock.yu@...>
 

Under multiple VQ use case, it is possible to have concurrent requests.
Added support to return multiple vq index from all vcpu.

Signed-off-by: Ong Hock Yu <ong.hock.yu@...>
---
drivers/vbs/vbs.c | 22 +++++++++++++++++-----
drivers/vbs/vbs_rng.c | 2 +-
include/linux/vbs/vbs.h | 8 ++++++--
3 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/drivers/vbs/vbs.c b/drivers/vbs/vbs.c
index 65b8a0bbe3d3..1cda5727a626 100644
--- a/drivers/vbs/vbs.c
+++ b/drivers/vbs/vbs.c
@@ -148,9 +148,11 @@ long virtio_dev_deregister(struct virtio_dev_info *dev)
return 0;
}

-int virtio_vq_index_get(struct virtio_dev_info *dev, unsigned long *ioreqs_map)
+int virtio_vqs_index_get(struct virtio_dev_info *dev,
+ unsigned long *ioreqs_map,
+ int *vqs_index, int max_vqs_index)
{
- int val = -1;
+ int idx = 0;
struct vhm_request *req;
int vcpu;

@@ -178,10 +180,20 @@ int virtio_vq_index_get(struct virtio_dev_info *dev, unsigned long *ioreqs_map)
} else {
pr_debug("%s: write request! type %d\n",
__func__, req->type);
+
+ if(idx == max_vqs_index)
+ {
+ pr_warn("%s: The allocated vqs size (%d) is smaller than \
+ the number of vcpu (%d)! This might caused the process \
+ of some requests be delayed.",__func__,max_vqs_index, \
+ dev->_ctx.max_vcpu);
+ break;
+ }
+
if (dev->io_range_type == PIO_RANGE)
- val = req->reqs.pio_request.value;
+ vqs_index[idx++] = req->reqs.pio_request.value;
else
- val = req->reqs.mmio_request.value;
+ vqs_index[idx++] = req->reqs.mmio_request.value;
}
smp_mb();
atomic_set(&req->processed, REQ_STATE_COMPLETE);
@@ -189,7 +201,7 @@ int virtio_vq_index_get(struct virtio_dev_info *dev, unsigned long *ioreqs_map)
}
}

- return val;
+ return idx;
}

static long virtio_vqs_info_set(struct virtio_dev_info *dev,
diff --git a/drivers/vbs/vbs_rng.c b/drivers/vbs/vbs_rng.c
index fd2bb27af66e..c5e28cc12c55 100644
--- a/drivers/vbs/vbs_rng.c
+++ b/drivers/vbs/vbs_rng.c
@@ -268,7 +268,7 @@ static int handle_kick(int client_id, unsigned long *ioreqs_map)
return -EINVAL;
}

- val = virtio_vq_index_get(&rng->dev, ioreqs_map);
+ virtio_vqs_index_get(&rng->dev, ioreqs_map, &val, 1);

if (val >= 0)
handle_vq_kick(rng, val);
diff --git a/include/linux/vbs/vbs.h b/include/linux/vbs/vbs.h
index 30df8ebf68a0..964bacac865c 100644
--- a/include/linux/vbs/vbs.h
+++ b/include/linux/vbs/vbs.h
@@ -262,7 +262,7 @@ long virtio_dev_register(struct virtio_dev_info *dev);
long virtio_dev_deregister(struct virtio_dev_info *dev);

/**
- * virtio_vq_index_get - get virtqueue index that frontend kicks
+ * virtio_vqs_index_get - get virtqueue indexes that frontend kicks
*
* This API is normally called in the VBS-K device's callback
* function, to get value write to the "kick" register from
@@ -270,10 +270,14 @@ long virtio_dev_deregister(struct virtio_dev_info *dev);
*
* @dev: Pointer to VBS-K device data struct
* @ioreqs_map: requests bitmap need to handle, provided by VHM
+ * @vqs_index: array to store the vq indexes
+ * @max_vqs_index: size of vqs_index array
*
* Return: >=0 on virtqueue index, <0 on error
*/
-int virtio_vq_index_get(struct virtio_dev_info *dev, unsigned long *ioreqs_map);
+int virtio_vqs_index_get(struct virtio_dev_info *dev,
+ unsigned long *ioreqs_map,
+ int *vqs_index, int max_vqs_index);

/**
* virtio_dev_reset - reset a VBS-K device
--
2.17.0


[PATCH 2/2] HV: acrntrace: Make the result easier to read

Kaige Fu
 

Originally, we don't format the output of analyser well. It is hard to read the
result.

This patch make every entry of the result align with the corresponding title to
make it easier for users to read.

Without patch:
Event NR_Exit NR_Exit/Sec Time Consumed(ms) Time Percentage
VMEXIT_INTERRUPT_WINDOW 78090 130.15 40 0.01
VMEXIT_CR_ACCESS 0 0.00 0 0.00
VMEXIT_APICV_ACCESS 0 0.00 0 0.00
VMEXIT_EXCEPTION_OR_NMI 0 0.00 0 0.00
VMEXIT_RDTSC 0 0.00 0 0.00

...

Vector Count NR_Exit/Sec
0x000000f0 82337 137.23
0x000000ef 247713 412.85

With patch:
Event NR_Exit NR_Exit/Sec Time Consumed(ms) Time percentage
VMEXIT_INTERRUPT_WINDOW 78090 130.15 40 0.01
VMEXIT_WRMSR 309085 515.14 128 0.02
VMEXIT_RDTSCP 0 0.00 0 0.00
VMEXIT_IO_INSTRUCTION 75250 125.42 12924 2.15
VMEXIT_EXTERNAL_INTERRUPT 330050 550.08 726 0.12

...

Vector Count NR_Exit/Sec
0x000000f0 82337 137.23
0x000000ef 247713 412.85

Signed-off-by: Kaige Fu <kaige.fu@...>
---
tools/acrntrace/scripts/irq_analyze.py | 6 +++---
tools/acrntrace/scripts/vmexit_analyze.py | 9 +++++----
2 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/tools/acrntrace/scripts/irq_analyze.py b/tools/acrntrace/scripts/irq_analyze.py
index f475da7..0d555aa 100755
--- a/tools/acrntrace/scripts/irq_analyze.py
+++ b/tools/acrntrace/scripts/irq_analyze.py
@@ -80,12 +80,12 @@ def generate_report(ofile, freq):

rt_sec = float(rt_cycle) / (float(freq) * 1000 * 1000)

- print ("\nVector \t\tCount \tNR_Exit/Sec")
+ print ("%-8s\t%-8s\t%-8s" % ("Vector", "Count", "NR_Exit/Sec"))
f_csv.writerow(['Vector', 'NR_Exit', 'NR_Exit/Sec'])
for e in IRQ_EXITS.keys():
pct = float(IRQ_EXITS[e]) / rt_sec
- print ("0x%08x \t %d \t%.2f" % (e, IRQ_EXITS[e], pct))
- f_csv.writerow([e, IRQ_EXITS[e], '%.2f' % pct])
+ print ("0x%08x\t%-8d\t%-8.2f" % (e, IRQ_EXITS[e], pct))
+ f_csv.writerow(['0x%08x' % e, IRQ_EXITS[e], '%.2f' % pct])

except IOError as err:
print ("Output File Error: " + str(err))
diff --git a/tools/acrntrace/scripts/vmexit_analyze.py b/tools/acrntrace/scripts/vmexit_analyze.py
index 0eee590..96dd40a 100755
--- a/tools/acrntrace/scripts/vmexit_analyze.py
+++ b/tools/acrntrace/scripts/vmexit_analyze.py
@@ -179,7 +179,8 @@ def generate_report(ofile, freq):
'%.3f' % (rt_ms),
'%d' % (freq)])

- print ("Event \tNR_Exit \tNR_Exit/Sec \tTime Consumed(ms) \tTime Percentage")
+ print ("%-28s\t%-12s\t%-12s\t%-18s\t%-16s" % ("Event", "NR_Exit",
+ "NR_Exit/Sec", "Time Consumed(ms)", "Time percentage"))
f_csv.writerow(['Exit_Reason',
'NR_Exit',
'NR_Exit/Sec',
@@ -190,7 +191,7 @@ def generate_report(ofile, freq):
ev_freq = float(NR_EXITS[event]) / rt_sec
pct = float(TIME_IN_EXIT[event]) * 100 / float(rt_ms)

- print ("%s \t%d \t%.2f \t%d \t%2.2f" %
+ print ("%-28s\t%-12d\t%-12.2f\t%-18d\t%-16.2f" %
(event, NR_EXITS[event], ev_freq, TIME_IN_EXIT[event], pct))
row = [event, NR_EXITS[event], '%.2f' % ev_freq, TIME_IN_EXIT[event],
'%2.2f' % (pct)]
@@ -198,8 +199,8 @@ def generate_report(ofile, freq):

ev_freq = float(TOTAL_NR_EXITS) / rt_sec
pct = float(total_exit_time) * 100 / float(rt_ms)
- print("Total \t%d \t%.2f \t%d \t%2.2f"
- % (TOTAL_NR_EXITS, ev_freq, total_exit_time, pct))
+ print("%-28s\t%-12d\t%-12.2f\t%-18d\t%-16.2f"
+ % ("Total", TOTAL_NR_EXITS, ev_freq, total_exit_time, pct))
row = ["Total", TOTAL_NR_EXITS, '%.2f' % ev_freq, total_exit_time,
'%2.2f' % (pct)]
f_csv.writerow(row)
--
2.7.4


[PATCH 1/2] HV: acrntrace: Output event time cost with milliseconds

Kaige Fu
 

Originally, we output "Time Consumed" with RTC cycles. It's not easy to read.
So, this patch convert it to milliseconds.

BTW, this patch also output "Total run time" with ms instead of original second.

Signed-off-by: Kaige Fu <kaige.fu@...>
---
tools/acrntrace/scripts/vmexit_analyze.py | 30 +++++++++++++++++++-----------
1 file changed, 19 insertions(+), 11 deletions(-)

diff --git a/tools/acrntrace/scripts/vmexit_analyze.py b/tools/acrntrace/scripts/vmexit_analyze.py
index 21cfa23..0eee590 100755
--- a/tools/acrntrace/scripts/vmexit_analyze.py
+++ b/tools/acrntrace/scripts/vmexit_analyze.py
@@ -80,7 +80,13 @@ TIME_IN_EXIT = {
# 4 * 64bit per trace entry
TRCREC = "QQQQ"

-def parse_trace_data(ifile):
+def tsc_to_ms(tsc, freq):
+ """convert tsc to milliseconds according freq
+ """
+
+ return float(tsc) / (float(freq) * 1000)
+
+def parse_trace_data(ifile, freq):
"""parse the trace data file
Args:
ifile: input trace data file
@@ -116,7 +122,8 @@ def parse_trace_data(ifile):
tsc_last_exit_period = tsc_enter - tsc_exit

if tsc_last_exit_period != 0:
- TIME_IN_EXIT[last_ev_id] += tsc_last_exit_period
+ TIME_IN_EXIT[last_ev_id] += \
+ tsc_to_ms(tsc_last_exit_period, freq)

elif event == VM_EXIT:
tsc_exit = tsc
@@ -157,30 +164,31 @@ def generate_report(ofile, freq):
tsc_end %d, tsc_begin %d"\
% (TSC_END, TSC_BEGIN)

- rt_sec = float(rt_cycle) / (float(freq) * 1000 * 1000)
+ rt_ms = tsc_to_ms(rt_cycle, freq)
+ rt_sec = float(rt_ms) / 1000.0

for event in LIST_EVENTS:
total_exit_time += TIME_IN_EXIT[event]

print ("Total run time: %d cycles" % (rt_cycle))
print ("TSC Freq: %f MHz" % (freq))
- print ("Total run time: %d sec" % (rt_sec))
+ print ("Total run time: %d ms" % (rt_ms))

- f_csv.writerow(['Run time(cycles)', 'Run time(Sec)', 'Freq(MHz)'])
+ f_csv.writerow(['Run time(cycles)', 'Run time(ms)', 'Freq(MHz)'])
f_csv.writerow(['%d' % (rt_cycle),
- '%.3f' % (rt_sec),
+ '%.3f' % (rt_ms),
'%d' % (freq)])

- print ("Event \tNR_Exit \tNR_Exit/Sec \tTime Consumed \tTime Percentage")
+ print ("Event \tNR_Exit \tNR_Exit/Sec \tTime Consumed(ms) \tTime Percentage")
f_csv.writerow(['Exit_Reason',
'NR_Exit',
'NR_Exit/Sec',
- 'Time Consumed(cycles)',
+ 'Time Consumed(ms)',
'Time Percentage'])

for event in LIST_EVENTS:
ev_freq = float(NR_EXITS[event]) / rt_sec
- pct = float(TIME_IN_EXIT[event]) * 100 / float(rt_cycle)
+ pct = float(TIME_IN_EXIT[event]) * 100 / float(rt_ms)

print ("%s \t%d \t%.2f \t%d \t%2.2f" %
(event, NR_EXITS[event], ev_freq, TIME_IN_EXIT[event], pct))
@@ -189,7 +197,7 @@ def generate_report(ofile, freq):
f_csv.writerow(row)

ev_freq = float(TOTAL_NR_EXITS) / rt_sec
- pct = float(total_exit_time) * 100 / float(rt_cycle)
+ pct = float(total_exit_time) * 100 / float(rt_ms)
print("Total \t%d \t%.2f \t%d \t%2.2f"
% (TOTAL_NR_EXITS, ev_freq, total_exit_time, pct))
row = ["Total", TOTAL_NR_EXITS, '%.2f' % ev_freq, total_exit_time,
@@ -211,6 +219,6 @@ def analyze_vm_exit(ifile, ofile):
print("VM exits analysis started... \n\tinput file: %s\n"
"\toutput file: %s.csv" % (ifile, ofile))

- parse_trace_data(ifile)
+ parse_trace_data(ifile, TSC_FREQ)
# save report to the output file
generate_report(ofile, TSC_FREQ)
--
2.7.4


[PATCH 0/2] Minor improvement of acrnalyser

Kaige Fu
 

This patch mainly focus on:
- Output "Time Consumed" and "Total run time" with milliseconds.
- Format the output to make the result entry align with the title.

Kaige Fu (2):
HV: acrntrace: Output event time cost with milliseconds
HV: acrntrace: Make the result easier to read

tools/acrntrace/scripts/irq_analyze.py | 6 ++---
tools/acrntrace/scripts/vmexit_analyze.py | 37 +++++++++++++++++++------------
2 files changed, 26 insertions(+), 17 deletions(-)

--
2.7.4


ACRN Project Technical Community Meeting: @ Weekly 9PM-10PM (China-Shanghai), 6AM-7AM (US-West Coast), 3PM-4PM (Europe-London)

Wang, Hongbo
 

Agenda (8/15): ACRN ACPI Management
 
WW Topic Presentator Status
WW21 ACRN roadmap introduction Ren, Jack Done
WW22 Patch submission process
ACRN feature list introduction
Wang, Hongbo
Ren, jack
Done
WW23 Memory Management Chen, Jascon Done
WW24 Boot flow and fast boot Wu, Binbin Done
WW25 Memory Management Chen, Jason C Done
WW26 Audio virtualization Li, Jocelyn Done
WW27 Trusty Security on ACRN Zhu, Bing’s team Done
WW28 Clear Linux and use on ACRN Du, Alek Done
WW29 GVT-g for ACRN (a.k.a AcrnGT) Gong, Zhipeng Done
WW30 Device pass-through Zhai, Edwin Done
WW31 ACRN logical partition Ren, Jack/Xu, Anthony Done
WW32 ACRN interrupt management Chen, Jason Done
WW33 ACRN ACPI virtualization Edwin Zhai Plan
WW34 ACRN P-state/C-state management Victor Sun Plan
WW35 ACRN Timer Li Fei Plan
WW36 CPU Virtualization Jason Chen Plan
WW37 ACRN S3/S5 management Fengwei Yin Plan
WW38 IPU Sharing Bandi, Kushal Plan
WW39 USB virtualization Yu Wang Plan
WW40 ACRN VT-d Binbin Wu Plan
WW41 ACRN GPIO virtualization Yu Wang Plan
 
 
 
Project ACRN: A flexible, light-weight, open source reference hypervisor for IoT devices
 
We're still in the early stages of forming this TSC, so instead we invite you to attend a weekly "Technical Community" meeting where we'll meet community members and talk about the ACRN project and plans. As we explore community interest and involvement opportunities, we'll (re)schedule these meetings at a time convenient to most attendees:
  • Meets every Wednesday, Starting May 30, 2018: 9PM-10PM (China-Shanghai), 6AM-7AM (US-West Coast)
  • Chairperson: Hongbo Wang, hongbo.wang@... (Intel)
  • Online conference link: https://zoom.us/j/880368975
  • Zoom Meeting ID: 880-368-975
  • Online conference phone:
  • US: +1 669 900 6833  or +1 646 558 8656   or +1 877 369 0926 (Toll Free) or +1 855 880 1246 (Toll Free)
  • China: +86 010 87833177  or 400 669 9381 (Toll Free)
  • Germany: +49 (0) 30 3080 6188  or +49 800 724 3138 (Toll Free)
  • Additional international phone numbers
  • Meeting Notes:
 
 
Best regards.
Hongbo
Tel: +86-21-6116 7445
MP: +86-1364 1793 689
 
 
 
 


[PATCH] VHM: add ioctl/hypercall for UOS intr data monitor

Minggui Cao
 

DM or VM monitor can use this ioctl/hypercall to get the UOS
interrupt count data, to check if it in normal status, and give
a response.

Signed-off-by: Minggui Cao <minggui.cao@...>
---
drivers/char/vhm/vhm_dev.c | 17 +++++++++++++++++
drivers/vhm/vhm_hypercall.c | 5 +++++
include/linux/vhm/acrn_hv_defs.h | 1 +
include/linux/vhm/vhm_hypercall.h | 1 +
include/linux/vhm/vhm_ioctl_defs.h | 1 +
5 files changed, 25 insertions(+)

diff --git a/drivers/char/vhm/vhm_dev.c b/drivers/char/vhm/vhm_dev.c
index c681ace..fc1e852 100644
--- a/drivers/char/vhm/vhm_dev.c
+++ b/drivers/char/vhm/vhm_dev.c
@@ -604,6 +604,23 @@ static long vhm_dev_ioctl(struct file *filep,
break;
}

+ case IC_VM_INTR_MONITOR: {
+ struct page *page;
+
+ ret = get_user_pages_fast(ioctl_param, 1, 1, &page);
+ if (unlikely(ret != 1) || (page == NULL)) {
+ pr_err("vhm-dev: failed to pin intr hdr buffer!\n");
+ return -ENOMEM;
+ }
+
+ ret = hcall_vm_intr_monitor(vm->vmid, page_to_phys(page));
+ if (ret < 0) {
+ pr_err("vhm-dev: monitor intr data err=%d\n", ret);
+ return -EFAULT;
+ }
+ break;
+ }
+
default:
pr_warn("Unknown IOCTL 0x%x\n", ioctl_num);
ret = 0;
diff --git a/drivers/vhm/vhm_hypercall.c b/drivers/vhm/vhm_hypercall.c
index 9a92d68..9a974e8 100644
--- a/drivers/vhm/vhm_hypercall.c
+++ b/drivers/vhm/vhm_hypercall.c
@@ -172,3 +172,8 @@ inline long hcall_vm_gpa2hpa(unsigned long vmid, unsigned long addr)
{
return acrn_hypercall2(HC_VM_GPA2HPA, vmid, addr);
}
+
+inline long hcall_vm_intr_monitor(unsigned long vmid, unsigned long addr)
+{
+ return acrn_hypercall2(HC_VM_INTR_MONITOR, vmid, addr);
+}
diff --git a/include/linux/vhm/acrn_hv_defs.h b/include/linux/vhm/acrn_hv_defs.h
index c12deaa..01494de 100644
--- a/include/linux/vhm/acrn_hv_defs.h
+++ b/include/linux/vhm/acrn_hv_defs.h
@@ -85,6 +85,7 @@
#define HC_DEASSERT_IRQLINE _HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x01)
#define HC_PULSE_IRQLINE _HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x02)
#define HC_INJECT_MSI _HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x03)
+#define HC_VM_INTR_MONITOR _HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x04UL)

/* DM ioreq management */
#define HC_ID_IOREQ_BASE 0x30UL
diff --git a/include/linux/vhm/vhm_hypercall.h b/include/linux/vhm/vhm_hypercall.h
index bc9feec..868541e 100644
--- a/include/linux/vhm/vhm_hypercall.h
+++ b/include/linux/vhm/vhm_hypercall.h
@@ -166,5 +166,6 @@ inline long hcall_reset_ptdev_intr_info(unsigned long vmid,
unsigned long pt_irq);
inline long hcall_remap_pci_msix(unsigned long vmid, unsigned long msi);
inline long hcall_vm_gpa2hpa(unsigned long vmid, unsigned long addr);
+inline long hcall_vm_intr_monitor(unsigned long vmid, unsigned long addr);

#endif /* __VHM_HYPERCALL_H__ */
diff --git a/include/linux/vhm/vhm_ioctl_defs.h b/include/linux/vhm/vhm_ioctl_defs.h
index 32e081a..042b8e9 100644
--- a/include/linux/vhm/vhm_ioctl_defs.h
+++ b/include/linux/vhm/vhm_ioctl_defs.h
@@ -80,6 +80,7 @@
#define IC_DEASSERT_IRQLINE _IC_ID(IC_ID, IC_ID_IRQ_BASE + 0x01)
#define IC_PULSE_IRQLINE _IC_ID(IC_ID, IC_ID_IRQ_BASE + 0x02)
#define IC_INJECT_MSI _IC_ID(IC_ID, IC_ID_IRQ_BASE + 0x03)
+#define IC_VM_INTR_MONITOR _IC_ID(IC_ID, IC_ID_IRQ_BASE + 0x04)

/* DM ioreq management */
#define IC_ID_IOREQ_BASE 0x30UL
--
2.7.4


[PATCH 2/2] DM: add monitor thread to check intrrupt status

Minggui Cao
 

intr monitor thread will check UOS interrupt status,
first to get intr data, and check if "interrupt storm" happen
as the condition setting, if happened, it will handle it as the
policy setting.

TODO: the policy setting and handling.

Signed-off-by: Minggui Cao <minggui.cao@...>
---
devicemodel/core/monitor.c | 128 ++++++++++++++++++++++++++++
devicemodel/core/vmmapi.c | 6 ++
devicemodel/include/public/acrn_common.h | 20 +++++
devicemodel/include/public/vhm_ioctl_defs.h | 1 +
devicemodel/include/vmmapi.h | 1 +
5 files changed, 156 insertions(+)

diff --git a/devicemodel/core/monitor.c b/devicemodel/core/monitor.c
index c5b41f1..58dcd61 100644
--- a/devicemodel/core/monitor.c
+++ b/devicemodel/core/monitor.c
@@ -15,11 +15,135 @@
#include <string.h>
#include <sys/stat.h>
#include <sys/queue.h>
+#include <unistd.h>
#include <pthread.h>
#include "dm.h"
#include "monitor.h"
#include "acrn_mngr.h"
#include "pm.h"
+#include "vmmapi.h"
+
+#define CHECK_PERIOD 10 /*10seconds*/
+#define INTR_STORM_THRESHOLD 1000000 /* 10K times per second */
+
+union intr_monitor_t {
+ struct acrn_intr_monitor monitor;
+ char reserved[4096];
+}__attribute__ ((aligned(4096)));
+
+static union intr_monitor_t intr_data;
+static uint64_t intr_cnt_buf[MAX_INTR_NUM];
+static pthread_t intr_check_pid;
+
+//#define INTR_CHECK_DEBUG
+#ifdef INTR_CHECK_DEBUG
+static FILE * dbg_file;
+#define DPRINTF(format, args...) \
+do { fprintf(dbg_file, format, args); fflush(dbg_file); } while (0)
+#else
+#define DPRINTF(format, arg...)
+#endif
+
+#ifdef INTR_CHECK_DEBUG
+static void write_intr_monitor_to_file(const struct acrn_intr_monitor *hdr)
+{
+ static int wr_cnt = 0;
+ int j;
+
+ wr_cnt++;
+ fprintf(dbg_file, "\n======%d time IRQs=%d=====\n", wr_cnt, hdr->intr_num);
+ fprintf(dbg_file, "IRQ\t\tCount\n");
+
+ for (j = 0; j < hdr->intr_num; j++) {
+ if (hdr->buffer[j] != 0)
+ fprintf(dbg_file, "%d\t\t%ld\n", j, hdr->buffer[j]);
+ }
+
+ fflush(dbg_file);
+}
+#endif
+
+static void *intr_check_thread(void *arg)
+{
+ struct vmctx *ctx = (struct vmctx *)arg;
+ struct acrn_intr_monitor *intr_hdr = &intr_data.monitor;
+ bool abnormal_checked = false;
+ int ret, i;
+
+#ifdef INTR_CHECK_DEBUG
+ dbg_file = fopen("/tmp/intr_log", "w+");
+#endif
+ sleep(CHECK_PERIOD);
+
+ /* first to get interrupt data */
+ intr_hdr->cmd = INTR_CMD_GET_DATA;
+ intr_hdr->intr_num = MAX_INTR_NUM;
+ memset(intr_hdr->buffer, 0, sizeof(uint64_t) * intr_hdr->intr_num);
+
+ ret = vm_intr_monitor(ctx, intr_hdr);
+ if (ret) {
+ DPRINTF("first get intr data failed, ret: %d\n", ret);
+ intr_check_pid = 0;
+ return NULL;
+ }
+
+ while (1) {
+#ifdef INTR_CHECK_DEBUG
+ write_intr_monitor_to_file(intr_hdr);
+#endif
+ memcpy(intr_cnt_buf, intr_hdr->buffer, sizeof(uint64_t) * intr_hdr->intr_num);
+ sleep(CHECK_PERIOD);
+
+ /* next time to get interrupt data */
+ memset(intr_hdr->buffer, 0, sizeof(uint64_t) * intr_hdr->intr_num);
+ ret = vm_intr_monitor(ctx, intr_hdr);
+ if (ret) {
+ DPRINTF("next get intr data failed, ret: %d\n", ret);
+ intr_check_pid = 0;
+ break;
+ }
+
+ /* calc the delta of the two times data */
+ for (i = 0; i < intr_hdr->intr_num; i++) {
+ uint64_t delta = intr_hdr->buffer[i] - intr_cnt_buf[i];
+
+ if (delta > INTR_STORM_THRESHOLD) {
+ /* TODO to handle the intr abnormal status as policy*/
+ DPRINTF("irq=%d, delta=%ld, in-buf=%ld, tmp=%ld\n", i,
+ delta, intr_hdr->buffer[i], intr_cnt_buf[i]);
+ intr_check_pid = 0;
+ abnormal_checked = true;
+ break;
+ }
+ }
+
+ if (abnormal_checked)
+ break;
+ }
+
+ return NULL;
+}
+
+static void start_intr_data_check(struct vmctx *ctx)
+{
+ int ret;
+
+ ret = pthread_create(&intr_check_pid, NULL, intr_check_thread, ctx);
+ if (ret) {
+ printf("failed %s %d\n", __FUNCTION__, __LINE__);
+ intr_check_pid = 0;
+ }
+
+ printf("start monitor interrupt data...\n");
+}
+
+static void stop_intr_data_check(void)
+{
+ if (intr_check_pid) {
+ pthread_cancel(intr_check_pid);
+ intr_check_pid = 0;
+ }
+}

/* helpers */
/* Check if @path is a directory, and create if not exist */
@@ -255,6 +379,8 @@ int monitor_init(struct vmctx *ctx)

monitor_register_vm_ops(&pmc_ops, ctx, "PMC_VM_OPs");

+ start_intr_data_check(ctx);
+
return 0;

handlers_err:
@@ -269,4 +395,6 @@ void monitor_close(void)
{
if (monitor_fd >= 0)
mngr_close(monitor_fd);
+
+ stop_intr_data_check();
}
diff --git a/devicemodel/core/vmmapi.c b/devicemodel/core/vmmapi.c
index 6a1310a..9419ad5 100644
--- a/devicemodel/core/vmmapi.c
+++ b/devicemodel/core/vmmapi.c
@@ -635,3 +635,9 @@ vm_get_cpu_state(struct vmctx *ctx, void *state_buf)
{
return ioctl(ctx->fd, IC_PM_GET_CPU_STATE, state_buf);
}
+
+int
+vm_intr_monitor(struct vmctx *ctx, void *intr_buf)
+{
+ return ioctl(ctx->fd, IC_VM_INTR_MONITOR, intr_buf);
+}
diff --git a/devicemodel/include/public/acrn_common.h b/devicemodel/include/public/acrn_common.h
index 0019d3a..6a43217 100644
--- a/devicemodel/include/public/acrn_common.h
+++ b/devicemodel/include/public/acrn_common.h
@@ -367,6 +367,26 @@ enum pm_cmd_type {
};

/**
+ * @brief Info to get a VM interrupt count data
+ *
+ * the parameter for HC_GET_VM_INTR_DATA hypercall
+ */
+#define MAX_INTR_NUM 320
+struct acrn_intr_monitor {
+ /** sub command for intr monitor */
+ uint32_t cmd;
+ /** the number of interrupts this buffer save */
+ uint32_t intr_num;
+
+ /** the buffer which save each interrupt count */
+ uint64_t buffer[MAX_INTR_NUM];
+} __aligned(8);
+
+/** cmd for intr monitor **/
+#define INTR_CMD_GET_DATA 0
+#define INTR_CMD_MASK_INT 1
+
+/**
* @}
*/
#endif /* _ACRN_COMMON_H_ */
diff --git a/devicemodel/include/public/vhm_ioctl_defs.h b/devicemodel/include/public/vhm_ioctl_defs.h
index 356d95c..158883e 100644
--- a/devicemodel/include/public/vhm_ioctl_defs.h
+++ b/devicemodel/include/public/vhm_ioctl_defs.h
@@ -80,6 +80,7 @@
#define IC_DEASSERT_IRQLINE _IC_ID(IC_ID, IC_ID_IRQ_BASE + 0x01)
#define IC_PULSE_IRQLINE _IC_ID(IC_ID, IC_ID_IRQ_BASE + 0x02)
#define IC_INJECT_MSI _IC_ID(IC_ID, IC_ID_IRQ_BASE + 0x03)
+#define IC_VM_INTR_MONITOR _IC_ID(IC_ID, IC_ID_IRQ_BASE + 0x04)

/* DM ioreq management */
#define IC_ID_IOREQ_BASE 0x30UL
diff --git a/devicemodel/include/vmmapi.h b/devicemodel/include/vmmapi.h
index 0f8709a..b9d08bb 100644
--- a/devicemodel/include/vmmapi.h
+++ b/devicemodel/include/vmmapi.h
@@ -148,6 +148,7 @@ int vm_reset_ptdev_intx_info(struct vmctx *ctx, int virt_pin, bool pic_pin);
int vm_create_vcpu(struct vmctx *ctx, uint16_t vcpu_id);

int vm_get_cpu_state(struct vmctx *ctx, void *state_buf);
+int vm_intr_monitor(struct vmctx *ctx, void *intr_buf);
void vm_stop_watchdog(struct vmctx *ctx);
void vm_reset_watchdog(struct vmctx *ctx);
#endif /* _VMMAPI_H_ */
--
2.7.4


[PATCH 1/2] HV: add hypercall to monitor UOS interrupt data

Minggui Cao
 

this hypercall can be used by DM or VMM manager
to monitor UOS interrupt work status; for example, to
check if there is an "interrupt storm", and do
some reactions according to its policy.

Tracked-on: https://github.com/projectacrn/acrn-hypervisor/issues/866
Signed-off-by: Minggui Cao <minggui.cao@...>
---
hypervisor/arch/x86/guest/vmcall.c | 4 ++++
hypervisor/arch/x86/irq.c | 23 +++++++++++++++++++++
hypervisor/common/hypercall.c | 34 ++++++++++++++++++++++++++++++++
hypervisor/include/arch/x86/irq.h | 3 +++
hypervisor/include/common/hypercall.h | 12 +++++++++++
hypervisor/include/public/acrn_common.h | 20 +++++++++++++++++++
hypervisor/include/public/acrn_hv_defs.h | 1 +
7 files changed, 97 insertions(+)

diff --git a/hypervisor/arch/x86/guest/vmcall.c b/hypervisor/arch/x86/guest/vmcall.c
index 3e3a7c7..cef1841 100644
--- a/hypervisor/arch/x86/guest/vmcall.c
+++ b/hypervisor/arch/x86/guest/vmcall.c
@@ -170,6 +170,10 @@ int vmcall_vmexit_handler(struct vcpu *vcpu)
ret = hcall_get_cpu_pm_state(vm, param1, param2);
break;

+ case HC_VM_INTR_MONITOR:
+ ret = hcall_vm_intr_monitor(vm, (uint16_t)param1, param2);
+ break;
+
default:
pr_err("op %d: Invalid hypercall\n", hypcall_id);
ret = -EPERM;
diff --git a/hypervisor/arch/x86/irq.c b/hypervisor/arch/x86/irq.c
index 14a629f..1728b63 100644
--- a/hypervisor/arch/x86/irq.c
+++ b/hypervisor/arch/x86/irq.c
@@ -732,6 +732,29 @@ void get_cpu_interrupt_info(char *str_arg, int str_max)
}
#endif /* HV_DEBUG */

+void get_vm_intr_data(const struct vm *target_vm, uint64_t *cnt_buf,
+ uint32_t intr_num)
+{
+ uint32_t irq, vector, i;
+ struct vcpu *vcpu;
+ struct irq_desc *desc;
+
+ for (irq = 0U; irq < intr_num; irq++) {
+ desc = irq_desc_array + irq;
+ vector = irq_to_vector(irq);
+
+ if ((desc->used != IRQ_NOT_ASSIGNED) &&
+ (vector != VECTOR_INVALID)) {
+
+ /* for timer & ipi not need to count? */
+ foreach_vcpu(i, target_vm, vcpu) {
+ cnt_buf[irq] += per_cpu(irq_count,
+ vcpu->pcpu_id)[irq];
+ }
+ }
+ }
+}
+
void interrupt_init(uint16_t pcpu_id)
{
struct host_idt_descriptor *idtd = &HOST_IDTR;
diff --git a/hypervisor/common/hypercall.c b/hypervisor/common/hypercall.c
index 280bfd0..c5bee04 100644
--- a/hypervisor/common/hypercall.c
+++ b/hypervisor/common/hypercall.c
@@ -893,3 +893,37 @@ int32_t hcall_get_cpu_pm_state(struct vm *vm, uint64_t cmd, uint64_t param)

}
}
+
+int32_t hcall_vm_intr_monitor(struct vm *vm, uint16_t vmid, uint64_t param)
+{
+ struct acrn_intr_monitor *intr_hdr;
+ uint64_t hpa;
+ struct vm *target_vm = get_vm_from_vmid(vmid);
+
+ if (!is_vm0(vm) || (target_vm == NULL)) {
+ return -1;
+ }
+
+ hpa = gpa2hpa(vm, param);
+ if (hpa == 0UL) {
+ pr_err("%s: invalid GPA.\n", __func__);
+ return -EINVAL;
+ }
+
+ intr_hdr = (struct acrn_intr_monitor *)HPA2HVA(hpa);
+
+ switch(intr_hdr->cmd) {
+ case INTR_CMD_GET_DATA:
+ if (intr_hdr->intr_num > NR_IRQS) {
+ intr_hdr->intr_num = NR_IRQS;
+ }
+
+ get_vm_intr_data(target_vm, intr_hdr->buffer, intr_hdr->intr_num);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
diff --git a/hypervisor/include/arch/x86/irq.h b/hypervisor/include/arch/x86/irq.h
index 7a677a3..1cc989d 100644
--- a/hypervisor/include/arch/x86/irq.h
+++ b/hypervisor/include/arch/x86/irq.h
@@ -99,4 +99,7 @@ void cancel_event_injection(struct vcpu *vcpu);
void get_cpu_interrupt_info(char *str_arg, int str_max);
#endif /* HV_DEBUG */

+void get_vm_intr_data(const struct vm *target_vm, uint64_t *cnt_buf,
+ uint32_t intr_num);
+
#endif /* ARCH_IRQ_H */
diff --git a/hypervisor/include/common/hypercall.h b/hypervisor/include/common/hypercall.h
index 7673c64..f9d8eeb 100644
--- a/hypervisor/include/common/hypercall.h
+++ b/hypervisor/include/common/hypercall.h
@@ -356,6 +356,18 @@ int32_t hcall_setup_sbuf(struct vm *vm, uint64_t param);
int32_t hcall_get_cpu_pm_state(struct vm *vm, uint64_t cmd, uint64_t param);

/**
+ * @brief Get VCPU a VM's interrupt count data.
+ *
+ * @param vm pointer to VM data structure
+ * @param vmid id of the VM
+ * @param param guest physical address. This gpa points to data structure of
+ * acrn_intr_monitor
+ *
+ * @return 0 on success, non-zero on error.
+ */
+int32_t hcall_vm_intr_monitor(struct vm *vm, uint16_t vmid, uint64_t param);
+
+/**
* @defgroup trusty_hypercall Trusty Hypercalls
*
* This is a special group that includes all hypercalls
diff --git a/hypervisor/include/public/acrn_common.h b/hypervisor/include/public/acrn_common.h
index df00de8..f52a8ab 100644
--- a/hypervisor/include/public/acrn_common.h
+++ b/hypervisor/include/public/acrn_common.h
@@ -463,6 +463,26 @@ enum pm_cmd_type {
};

/**
+ * @brief Info to get a VM interrupt count data
+ *
+ * the parameter for HC_GET_VM_INTR_DATA hypercall
+ */
+#define MAX_INTR_NUM 320
+struct acrn_intr_monitor {
+ /** sub command for intr monitor */
+ uint32_t cmd;
+ /** the number of interrupts this buffer save */
+ uint32_t intr_num;
+
+ /** the buffer which save each interrupt count */
+ uint64_t buffer[MAX_INTR_NUM];
+} __aligned(8);
+
+/** cmd for intr monitor **/
+#define INTR_CMD_GET_DATA 0
+#define INTR_CMD_MASK_INT 1
+
+/**
* @}
*/
#endif /* ACRN_COMMON_H */
diff --git a/hypervisor/include/public/acrn_hv_defs.h b/hypervisor/include/public/acrn_hv_defs.h
index d4477d2..19c1ce1 100644
--- a/hypervisor/include/public/acrn_hv_defs.h
+++ b/hypervisor/include/public/acrn_hv_defs.h
@@ -43,6 +43,7 @@
#define HC_DEASSERT_IRQLINE BASE_HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x01UL)
#define HC_PULSE_IRQLINE BASE_HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x02UL)
#define HC_INJECT_MSI BASE_HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x03UL)
+#define HC_VM_INTR_MONITOR BASE_HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x04UL)

/* DM ioreq management */
#define HC_ID_IOREQ_BASE 0x30UL
--
2.7.4


[PATCH 0/2] *** interrupt storm mitigation ***

Minggui Cao
 

add the UOS interrupt data check first.
*** BLURB HERE ***

Minggui Cao (2):
HV: add hypercall to monitor UOS interrupt data
DM: add monitor thread to check intrrupt status

devicemodel/core/monitor.c | 128 ++++++++++++++++++++++++++++
devicemodel/core/vmmapi.c | 6 ++
devicemodel/include/public/acrn_common.h | 20 +++++
devicemodel/include/public/vhm_ioctl_defs.h | 1 +
devicemodel/include/vmmapi.h | 1 +
hypervisor/arch/x86/guest/vmcall.c | 4 +
hypervisor/arch/x86/irq.c | 23 +++++
hypervisor/common/hypercall.c | 34 ++++++++
hypervisor/include/arch/x86/irq.h | 3 +
hypervisor/include/common/hypercall.h | 12 +++
hypervisor/include/public/acrn_common.h | 20 +++++
hypervisor/include/public/acrn_hv_defs.h | 1 +
12 files changed, 253 insertions(+)

--
2.7.4


Re: [PATCH v4 1/1] vbs: fix virtio_vq_index_get func handling of multi VQ concurrent request.

Shuo A Liu
 

Hi OH,

On Mon 13.Aug'18 at 19:22:28 +0000, Ong Hock Yu wrote:
Under multiple VQ use case, it is possible to have concurrent requests.
Added support to return multiple vq index from all vcpu.

Change-Id: I558941fe9e1f524b91358fb9bec4c96277fd5681
Remove this line.

Signed-off-by: Ong Hock Yu <ong.hock.yu@...>
---
drivers/vbs/vbs.c | 20 ++++++++++++++------
drivers/vbs/vbs_rng.c | 2 +-
include/linux/vbs/vbs.h | 8 ++++++--
3 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/drivers/vbs/vbs.c b/drivers/vbs/vbs.c
index 65b8a0bbe3d3..d3dcbe77ebee 100644
--- a/drivers/vbs/vbs.c
+++ b/drivers/vbs/vbs.c
@@ -148,9 +148,11 @@ long virtio_dev_deregister(struct virtio_dev_info *dev)
return 0;
}

-int virtio_vq_index_get(struct virtio_dev_info *dev, unsigned long *ioreqs_map)
+int virtio_vqs_index_get(struct virtio_dev_info *dev,
+ unsigned long *ioreqs_map,
+ int *vqs_index, int max_vqs_index)
{
- int val = -1;
+ int idx = 0;
struct vhm_request *req;
int vcpu;

@@ -159,7 +161,13 @@ int virtio_vq_index_get(struct virtio_dev_info *dev, unsigned long *ioreqs_map)
return -EINVAL;
}

- while (1) {
+ if(max_vqs_index < dev->_ctx.max_vcpu)
+ pr_info("%s: The allocated vqs size (%d) is smaller than the
+ number of vcpu (%d)! This might caused the process of
+ some requests be delayed.",__func__,max_vqs_index,
+ dev->_ctx.max_vcpu);
+
This might casue a lots of logs for normal case. The corner case happens
rarely.
How about
while (1) {
vcpu = find_first_bit(ioreqs_map, dev->_ctx.max_vcpu);
if (vcpu == dev->_ctx.max_vcpu)
break;
...
if (atomic_read(&req->processed) == REQ_STATE_PROCESSING &&
req->client == dev->_ctx.vhm_client_id) {
if (idx == max_vqs_index) {
pr_warn("xxx");
break;
}
...
}
}

?

Thanks
shuo

+ while (idx < max_vqs_index) {
vcpu = find_first_bit(ioreqs_map, dev->_ctx.max_vcpu);
if (vcpu == dev->_ctx.max_vcpu)
break;
@@ -179,9 +187,9 @@ int virtio_vq_index_get(struct virtio_dev_info *dev, unsigned long *ioreqs_map)
pr_debug("%s: write request! type %d\n",
__func__, req->type);
if (dev->io_range_type == PIO_RANGE)
- val = req->reqs.pio_request.value;
+ vqs_index[idx++] = req->reqs.pio_request.value;
else
- val = req->reqs.mmio_request.value;
+ vqs_index[idx++] = req->reqs.mmio_request.value;
}
smp_mb();
atomic_set(&req->processed, REQ_STATE_COMPLETE);
@@ -189,7 +197,7 @@ int virtio_vq_index_get(struct virtio_dev_info *dev, unsigned long *ioreqs_map)
}
}

- return val;
+ return idx;
}

static long virtio_vqs_info_set(struct virtio_dev_info *dev,
diff --git a/drivers/vbs/vbs_rng.c b/drivers/vbs/vbs_rng.c
index fd2bb27af66e..c5e28cc12c55 100644
--- a/drivers/vbs/vbs_rng.c
+++ b/drivers/vbs/vbs_rng.c
@@ -268,7 +268,7 @@ static int handle_kick(int client_id, unsigned long *ioreqs_map)
return -EINVAL;
}

- val = virtio_vq_index_get(&rng->dev, ioreqs_map);
+ virtio_vqs_index_get(&rng->dev, ioreqs_map, &val, 1);

if (val >= 0)
handle_vq_kick(rng, val);
diff --git a/include/linux/vbs/vbs.h b/include/linux/vbs/vbs.h
index 30df8ebf68a0..964bacac865c 100644
--- a/include/linux/vbs/vbs.h
+++ b/include/linux/vbs/vbs.h
@@ -262,7 +262,7 @@ long virtio_dev_register(struct virtio_dev_info *dev);
long virtio_dev_deregister(struct virtio_dev_info *dev);

/**
- * virtio_vq_index_get - get virtqueue index that frontend kicks
+ * virtio_vqs_index_get - get virtqueue indexes that frontend kicks
*
* This API is normally called in the VBS-K device's callback
* function, to get value write to the "kick" register from
@@ -270,10 +270,14 @@ long virtio_dev_deregister(struct virtio_dev_info *dev);
*
* @dev: Pointer to VBS-K device data struct
* @ioreqs_map: requests bitmap need to handle, provided by VHM
+ * @vqs_index: array to store the vq indexes
+ * @max_vqs_index: size of vqs_index array
*
* Return: >=0 on virtqueue index, <0 on error
*/
-int virtio_vq_index_get(struct virtio_dev_info *dev, unsigned long *ioreqs_map);
+int virtio_vqs_index_get(struct virtio_dev_info *dev,
+ unsigned long *ioreqs_map,
+ int *vqs_index, int max_vqs_index);

/**
* virtio_dev_reset - reset a VBS-K device
--
2.17.0




Re: [PATCH v2] HV: Add const qualifiers where required

Junjie Mao
 

Arindam Roy <arindam.roy@...> writes:

V1:
In order to better comply with MISRA C,
add const qualifiers whereeven required.
In the patch, these are being added to pointers
which are normally used in "get" functions.

V2: Corrected the issues in the patch
pointed by Junjie in his review comments.
Moved the const qualifiers to the correct
places. Removed some changes which are not
needed.

Signed-off-by: Arindam Roy <arindam.roy@...>
Reviewed-by: Junjie Mao <junjie.mao@...>

Please also include the scope of this patch in your commit log. I think
this patch covers the const qualifiers in some sources, but not
all. Stating what you changed explicitly can help others review for
completeness.

---
hypervisor/arch/x86/cpu_state_tbl.c | 2 +-
hypervisor/arch/x86/cpuid.c | 6 +++---
hypervisor/arch/x86/ept.c | 14 +++++++-------
hypervisor/arch/x86/guest/guest.c | 10 +++++-----
hypervisor/include/arch/x86/cpuid.h | 2 +-
hypervisor/include/arch/x86/guest/guest.h | 6 +++---
hypervisor/include/arch/x86/io.h | 18 +++++++++---------
hypervisor/include/arch/x86/mmu.h | 22 +++++++++++-----------
hypervisor/include/arch/x86/pgtable.h | 8 ++++----
hypervisor/include/arch/x86/vmx.h | 2 +-
10 files changed, 45 insertions(+), 45 deletions(-)

diff --git a/hypervisor/arch/x86/cpu_state_tbl.c b/hypervisor/arch/x86/cpu_state_tbl.c
index 6f192dad..80093c96 100644
--- a/hypervisor/arch/x86/cpu_state_tbl.c
+++ b/hypervisor/arch/x86/cpu_state_tbl.c
@@ -89,7 +89,7 @@ static const struct cpu_state_table {
}
};

-static int get_state_tbl_idx(char *cpuname)
+static int get_state_tbl_idx(const char *cpuname)
{
int i;
int count = ARRAY_SIZE(cpu_state_tbl);
diff --git a/hypervisor/arch/x86/cpuid.c b/hypervisor/arch/x86/cpuid.c
index 18ebfcc7..215bdcce 100644
--- a/hypervisor/arch/x86/cpuid.c
+++ b/hypervisor/arch/x86/cpuid.c
@@ -8,7 +8,7 @@

extern bool x2apic_enabled;

-static inline struct vcpuid_entry *find_vcpuid_entry(struct vcpu *vcpu,
+static inline struct vcpuid_entry *find_vcpuid_entry(const struct vcpu *vcpu,
uint32_t leaf_arg, uint32_t subleaf)
{
uint32_t i = 0U, nr, half;
@@ -66,7 +66,7 @@ static inline struct vcpuid_entry *find_vcpuid_entry(struct vcpu *vcpu,
}

static inline int set_vcpuid_entry(struct vm *vm,
- struct vcpuid_entry *entry)
+ const struct vcpuid_entry *entry)
{
struct vcpuid_entry *tmp;
size_t entry_size = sizeof(struct vcpuid_entry);
@@ -273,7 +273,7 @@ int set_vcpuid_entries(struct vm *vm)
return 0;
}

-void guest_cpuid(struct vcpu *vcpu,
+void guest_cpuid(const struct vcpu *vcpu,
uint32_t *eax, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx)
{
diff --git a/hypervisor/arch/x86/ept.c b/hypervisor/arch/x86/ept.c
index a7bcb43e..6a327574 100644
--- a/hypervisor/arch/x86/ept.c
+++ b/hypervisor/arch/x86/ept.c
@@ -10,7 +10,7 @@

#define ACRN_DBG_EPT 6U

-static uint64_t find_next_table(uint32_t table_offset, void *table_base)
+static uint64_t find_next_table(uint32_t table_offset, const void *table_base)
{
uint64_t table_entry;
uint64_t table_present;
@@ -100,7 +100,7 @@ void destroy_ept(struct vm *vm)
free_ept_mem(vm->arch_vm.m2p);
}

-uint64_t local_gpa2hpa(struct vm *vm, uint64_t gpa, uint32_t *size)
+uint64_t local_gpa2hpa(const struct vm *vm, uint64_t gpa, uint32_t *size)
{
uint64_t hpa = 0UL;
uint64_t *pgentry, pg_size = 0UL;
@@ -124,12 +124,12 @@ uint64_t local_gpa2hpa(struct vm *vm, uint64_t gpa, uint32_t *size)
}

/* using return value 0 as failure, make sure guest will not use hpa 0 */
-uint64_t gpa2hpa(struct vm *vm, uint64_t gpa)
+uint64_t gpa2hpa(const struct vm *vm, uint64_t gpa)
{
return local_gpa2hpa(vm, gpa, NULL);
}

-uint64_t hpa2gpa(struct vm *vm, uint64_t hpa)
+uint64_t hpa2gpa(const struct vm *vm, uint64_t hpa)
{
uint64_t *pgentry, pg_size = 0UL;

@@ -284,7 +284,7 @@ int ept_misconfig_vmexit_handler(__unused struct vcpu *vcpu)
return status;
}

-int ept_mr_add(struct vm *vm, uint64_t hpa_arg,
+int ept_mr_add(const struct vm *vm, uint64_t hpa_arg,
uint64_t gpa_arg, uint64_t size, uint32_t prot_arg)
{
struct mem_map_params map_params;
@@ -323,7 +323,7 @@ int ept_mr_add(struct vm *vm, uint64_t hpa_arg,
return 0;
}

-int ept_mr_modify(struct vm *vm, uint64_t *pml4_page,
+int ept_mr_modify(const struct vm *vm, uint64_t *pml4_page,
uint64_t gpa, uint64_t size,
uint64_t prot_set, uint64_t prot_clr)
{
@@ -341,7 +341,7 @@ int ept_mr_modify(struct vm *vm, uint64_t *pml4_page,
return ret;
}

-int ept_mr_del(struct vm *vm, uint64_t *pml4_page,
+int ept_mr_del(const struct vm *vm, uint64_t *pml4_page,
uint64_t gpa, uint64_t size)
{
struct vcpu *vcpu;
diff --git a/hypervisor/arch/x86/guest/guest.c b/hypervisor/arch/x86/guest/guest.c
index dfb33bca..47692e30 100644
--- a/hypervisor/arch/x86/guest/guest.c
+++ b/hypervisor/arch/x86/guest/guest.c
@@ -46,7 +46,7 @@ uint64_t vcpumask2pcpumask(struct vm *vm, uint64_t vdmask)
return dmask;
}

-bool vm_lapic_disabled(struct vm *vm)
+bool vm_lapic_disabled(const struct vm *vm)
{
uint16_t i;
struct vcpu *vcpu;
@@ -276,7 +276,7 @@ int gva2gpa(struct vcpu *vcpu, uint64_t gva, uint64_t *gpa,
return ret;
}

-static inline uint32_t local_copy_gpa(struct vm *vm, void *h_ptr, uint64_t gpa,
+static inline uint32_t local_copy_gpa(const struct vm *vm, void *h_ptr, uint64_t gpa,
uint32_t size, uint32_t fix_pg_size, bool cp_from_vm)
{
uint64_t hpa;
@@ -308,7 +308,7 @@ static inline uint32_t local_copy_gpa(struct vm *vm, void *h_ptr, uint64_t gpa,
return len;
}

-static inline int copy_gpa(struct vm *vm, void *h_ptr_arg, uint64_t gpa_arg,
+static inline int copy_gpa(const struct vm *vm, void *h_ptr_arg, uint64_t gpa_arg,
uint32_t size_arg, bool cp_from_vm)
{
void *h_ptr = h_ptr_arg;
@@ -385,12 +385,12 @@ static inline int copy_gva(struct vcpu *vcpu, void *h_ptr_arg, uint64_t gva_arg,
* - some other gpa from hypercall parameters, VHM should make sure it's
* continuous
*/
-int copy_from_gpa(struct vm *vm, void *h_ptr, uint64_t gpa, uint32_t size)
+int copy_from_gpa(const struct vm *vm, void *h_ptr, uint64_t gpa, uint32_t size)
{
return copy_gpa(vm, h_ptr, gpa, size, 1);
}

-int copy_to_gpa(struct vm *vm, void *h_ptr, uint64_t gpa, uint32_t size)
+int copy_to_gpa(const struct vm *vm, void *h_ptr, uint64_t gpa, uint32_t size)
{
return copy_gpa(vm, h_ptr, gpa, size, 0);
}
diff --git a/hypervisor/include/arch/x86/cpuid.h b/hypervisor/include/arch/x86/cpuid.h
index 8fef50fc..35003928 100644
--- a/hypervisor/include/arch/x86/cpuid.h
+++ b/hypervisor/include/arch/x86/cpuid.h
@@ -132,7 +132,7 @@ static inline void cpuid_subleaf(uint32_t leaf, uint32_t subleaf,
}

int set_vcpuid_entries(struct vm *vm);
-void guest_cpuid(struct vcpu *vcpu,
+void guest_cpuid(const struct vcpu *vcpu,
uint32_t *eax, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx);

diff --git a/hypervisor/include/arch/x86/guest/guest.h b/hypervisor/include/arch/x86/guest/guest.h
index 0e291a75..46ef2143 100644
--- a/hypervisor/include/arch/x86/guest/guest.h
+++ b/hypervisor/include/arch/x86/guest/guest.h
@@ -93,7 +93,7 @@ enum vm_paging_mode {
/*
* VM related APIs
*/
-bool vm_lapic_disabled(struct vm *vm);
+bool vm_lapic_disabled(const struct vm *vm);
uint64_t vcpumask2pcpumask(struct vm *vm, uint64_t vdmask);

int gva2gpa(struct vcpu *vcpu, uint64_t gva, uint64_t *gpa, uint32_t *err_code);
@@ -121,8 +121,8 @@ int general_sw_loader(struct vm *vm, struct vcpu *vcpu);
typedef int (*vm_sw_loader_t)(struct vm *vm, struct vcpu *vcpu);
extern vm_sw_loader_t vm_sw_loader;

-int copy_from_gpa(struct vm *vm, void *h_ptr, uint64_t gpa, uint32_t size);
-int copy_to_gpa(struct vm *vm, void *h_ptr, uint64_t gpa, uint32_t size);
+int copy_from_gpa(const struct vm *vm, void *h_ptr, uint64_t gpa, uint32_t size);
+int copy_to_gpa(const struct vm *vm, void *h_ptr, uint64_t gpa, uint32_t size);
int copy_from_gva(struct vcpu *vcpu, void *h_ptr, uint64_t gva,
uint32_t size, uint32_t *err_code, uint64_t *fault_addr);
int copy_to_gva(struct vcpu *vcpu, void *h_ptr, uint64_t gva,
diff --git a/hypervisor/include/arch/x86/io.h b/hypervisor/include/arch/x86/io.h
index e2f4a8ec..e13dcb34 100644
--- a/hypervisor/include/arch/x86/io.h
+++ b/hypervisor/include/arch/x86/io.h
@@ -81,7 +81,7 @@ static inline uint32_t pio_read(uint16_t addr, size_t sz)
* @param value The 32 bit value to write.
* @param addr The memory address to write to.
*/
-static inline void mmio_write32(uint32_t value, void *addr)
+static inline void mmio_write32(uint32_t value, const void *addr)
{
volatile uint32_t *addr32 = (volatile uint32_t *)addr;
*addr32 = value;
@@ -92,7 +92,7 @@ static inline void mmio_write32(uint32_t value, void *addr)
* @param value The 16 bit value to write.
* @param addr The memory address to write to.
*/
-static inline void mmio_write16(uint16_t value, void *addr)
+static inline void mmio_write16(uint16_t value, const void *addr)
{
volatile uint16_t *addr16 = (volatile uint16_t *)addr;
*addr16 = value;
@@ -103,7 +103,7 @@ static inline void mmio_write16(uint16_t value, void *addr)
* @param value The 8 bit value to write.
* @param addr The memory address to write to.
*/
-static inline void mmio_write8(uint8_t value, void *addr)
+static inline void mmio_write8(uint8_t value, const void *addr)
{
volatile uint8_t *addr8 = (volatile uint8_t *)addr;
*addr8 = value;
@@ -115,7 +115,7 @@ static inline void mmio_write8(uint8_t value, void *addr)
*
* @return The 32 bit value read from the given address.
*/
-static inline uint32_t mmio_read32(void *addr)
+static inline uint32_t mmio_read32(const void *addr)
{
return *((volatile uint32_t *)addr);
}
@@ -126,7 +126,7 @@ static inline uint32_t mmio_read32(void *addr)
*
* @return The 16 bit value read from the given address.
*/
-static inline uint16_t mmio_read16(void *addr)
+static inline uint16_t mmio_read16(const void *addr)
{
return *((volatile uint16_t *)addr);
}
@@ -137,7 +137,7 @@ static inline uint16_t mmio_read16(void *addr)
*
* @return The 8 bit value read from the given address.
*/
-static inline uint8_t mmio_read8(void *addr)
+static inline uint8_t mmio_read8(const void *addr)
{
return *((volatile uint8_t *)addr);
}
@@ -150,7 +150,7 @@ static inline uint8_t mmio_read8(void *addr)
* @param mask The mask to apply to the value read.
* @param value The 32 bit value to write.
*/
-static inline void set32(void *addr, uint32_t mask, uint32_t value)
+static inline void set32(const void *addr, uint32_t mask, uint32_t value)
{
uint32_t temp_val;

@@ -165,7 +165,7 @@ static inline void set32(void *addr, uint32_t mask, uint32_t value)
* @param mask The mask to apply to the value read.
* @param value The 16 bit value to write.
*/
-static inline void set16(void *addr, uint16_t mask, uint16_t value)
+static inline void set16(const void *addr, uint16_t mask, uint16_t value)
{
uint16_t temp_val;

@@ -180,7 +180,7 @@ static inline void set16(void *addr, uint16_t mask, uint16_t value)
* @param mask The mask to apply to the value read.
* @param value The 8 bit value to write.
*/
-static inline void set8(void *addr, uint8_t mask, uint8_t value)
+static inline void set8(const void *addr, uint8_t mask, uint8_t value)
{
uint8_t temp_val;

diff --git a/hypervisor/include/arch/x86/mmu.h b/hypervisor/include/arch/x86/mmu.h
index 27699035..9918efe0 100644
--- a/hypervisor/include/arch/x86/mmu.h
+++ b/hypervisor/include/arch/x86/mmu.h
@@ -259,27 +259,27 @@ enum _page_table_present {
#define PAGE_SIZE_1G MEM_1G

/* Inline functions for reading/writing memory */
-static inline uint8_t mem_read8(void *addr)
+static inline uint8_t mem_read8(const void *addr)
{
return *(volatile uint8_t *)(addr);
}

-static inline uint16_t mem_read16(void *addr)
+static inline uint16_t mem_read16(const void *addr)
{
return *(volatile uint16_t *)(addr);
}

-static inline uint32_t mem_read32(void *addr)
+static inline uint32_t mem_read32(const void *addr)
{
return *(volatile uint32_t *)(addr);
}

-static inline uint64_t mem_read64(void *addr)
+static inline uint64_t mem_read64(const void *addr)
{
return *(volatile uint64_t *)(addr);
}

-static inline void mem_write8(void *addr, uint8_t data)
+static inline void mem_write8(const void *addr, uint8_t data)
{
volatile uint8_t *addr8 = (volatile uint8_t *)addr;
*addr8 = data;
@@ -379,15 +379,15 @@ static inline void clflush(volatile void *p)
bool is_ept_supported(void);
uint64_t create_guest_initial_paging(struct vm *vm);
void destroy_ept(struct vm *vm);
-uint64_t gpa2hpa(struct vm *vm, uint64_t gpa);
-uint64_t local_gpa2hpa(struct vm *vm, uint64_t gpa, uint32_t *size);
-uint64_t hpa2gpa(struct vm *vm, uint64_t hpa);
-int ept_mr_add(struct vm *vm, uint64_t hpa_arg,
+uint64_t gpa2hpa(const struct vm *vm, uint64_t gpa);
+uint64_t local_gpa2hpa(const struct vm *vm, uint64_t gpa, uint32_t *size);
+uint64_t hpa2gpa(const struct vm *vm, uint64_t hpa);
+int ept_mr_add(const struct vm *vm, uint64_t hpa_arg,
uint64_t gpa_arg, uint64_t size, uint32_t prot_arg);
-int ept_mr_modify(struct vm *vm, uint64_t *pml4_page,
+int ept_mr_modify(const struct vm *vm, uint64_t *pml4_page,
uint64_t gpa, uint64_t size,
uint64_t prot_set, uint64_t prot_clr);
-int ept_mr_del(struct vm *vm, uint64_t *pml4_page,
+int ept_mr_del(const struct vm *vm, uint64_t *pml4_page,
uint64_t gpa, uint64_t size);
void free_ept_mem(void *pml4_addr);
int ept_violation_vmexit_handler(struct vcpu *vcpu);
diff --git a/hypervisor/include/arch/x86/pgtable.h b/hypervisor/include/arch/x86/pgtable.h
index 51733611..ffa3b179 100644
--- a/hypervisor/include/arch/x86/pgtable.h
+++ b/hypervisor/include/arch/x86/pgtable.h
@@ -53,17 +53,17 @@ static inline uint64_t *pml4e_offset(uint64_t *pml4_page, uint64_t addr)
return pml4_page + pml4e_index(addr);
}

-static inline uint64_t *pdpte_offset(uint64_t *pml4e, uint64_t addr)
+static inline uint64_t *pdpte_offset(const uint64_t *pml4e, uint64_t addr)
{
return pml4e_page_vaddr(*pml4e) + pdpte_index(addr);
}

-static inline uint64_t *pde_offset(uint64_t *pdpte, uint64_t addr)
+static inline uint64_t *pde_offset(const uint64_t *pdpte, uint64_t addr)
{
return pdpte_page_vaddr(*pdpte) + pde_index(addr);
}

-static inline uint64_t *pte_offset(uint64_t *pde, uint64_t addr)
+static inline uint64_t *pte_offset(const uint64_t *pde, uint64_t addr)
{
return pde_page_vaddr(*pde) + pte_index(addr);
}
@@ -71,7 +71,7 @@ static inline uint64_t *pte_offset(uint64_t *pde, uint64_t addr)
/*
* pgentry may means pml4e/pdpte/pde/pte
*/
-static inline uint64_t get_pgentry(uint64_t *pte)
+static inline uint64_t get_pgentry(const uint64_t *pte)
{
return *pte;
}
diff --git a/hypervisor/include/arch/x86/vmx.h b/hypervisor/include/arch/x86/vmx.h
index 938a2017..ede9cf7b 100644
--- a/hypervisor/include/arch/x86/vmx.h
+++ b/hypervisor/include/arch/x86/vmx.h
@@ -449,7 +449,7 @@ int vmx_wrmsr_pat(struct vcpu *vcpu, uint64_t value);
int vmx_write_cr0(struct vcpu *vcpu, uint64_t cr0);
int vmx_write_cr4(struct vcpu *vcpu, uint64_t cr4);

-static inline enum vm_cpu_mode get_vcpu_mode(struct vcpu *vcpu)
+static inline enum vm_cpu_mode get_vcpu_mode(const struct vcpu *vcpu)
{
return vcpu->arch_vcpu.cpu_mode;
}


Re: [PATCH v2] HV: Enclose debug specific code with #ifdef HV_DEBUG #ifdef

Kaige Fu
 

On 08-14 Tue 03:44, Eddie Dong wrote:


-----Original Message-----
From: acrn-dev@...
[mailto:acrn-dev@...] On Behalf Of Kaige Fu
Sent: Tuesday, August 14, 2018 10:58 AM
To: acrn-dev@...
Subject: [acrn-dev] [PATCH v2] HV: Enclose debug specific code with #ifdef
HV_DEBUG

Thare some debug specific code which don't run on release version, such as
vmexit_time, vmexit_cnt, sbuf related codes, etc...

This patch enclose these codes with #ifdef HV_DEBUG.

---
v1 -> v2:
- Enclose suf related codes with #ifdef HV_DEBUG

Signed-off-by: Kaige Fu <kaige.fu@...>
---
hypervisor/common/hv_main.c | 12 +++++++++---
hypervisor/common/hypercall.c | 7 +++++++
hypervisor/include/arch/x86/per_cpu.h | 4 +++-
3 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/hypervisor/common/hv_main.c b/hypervisor/common/hv_main.c
index 15f1d9d..e3657f9 100644
--- a/hypervisor/common/hv_main.c
+++ b/hypervisor/common/hv_main.c
@@ -59,11 +59,13 @@ void vcpu_thread(struct vcpu *vcpu)
continue;
}

+#ifdef HV_DEBUG
vmexit_end = rdtsc();
if (vmexit_begin != 0UL) {
per_cpu(vmexit_time, vcpu->pcpu_id)[basic_exit_reason]
+= (vmexit_end - vmexit_begin);
}
+#endif
TRACE_2L(TRACE_VM_ENTER, 0UL, 0UL);

/* Restore guest TSC_AUX */
@@ -79,7 +81,9 @@ void vcpu_thread(struct vcpu *vcpu)
continue;
}

+#ifdef HV_DEBUG
vmexit_begin = rdtsc();
+#endif

vcpu->arch_vcpu.nrexits++;
/* Save guest TSC_AUX */
@@ -90,16 +94,18 @@ void vcpu_thread(struct vcpu *vcpu)
CPU_IRQ_ENABLE();
/* Dispatch handler */
ret = vmexit_handler(vcpu);
+ basic_exit_reason = vcpu->arch_vcpu.exit_reason & 0xFFFFU;
if (ret < 0) {
pr_fatal("dispatch VM exit handler failed for reason"
- " %d, ret = %d!",
- vcpu->arch_vcpu.exit_reason & 0xFFFFU, ret);
+ " %d, ret = %d!", basic_exit_reason, ret);
vcpu_inject_gp(vcpu, 0U);
continue;
}

- basic_exit_reason = vcpu->arch_vcpu.exit_reason & 0xFFFFU;
+#ifdef HV_DEBUG
per_cpu(vmexit_cnt, vcpu->pcpu_id)[basic_exit_reason]++;
+#endif
+
TRACE_2L(TRACE_VM_EXIT, basic_exit_reason,
vcpu_get_rip(vcpu));
} while (1);
}
diff --git a/hypervisor/common/hypercall.c
b/hypervisor/common/hypercall.c index f8efb35..4d9a23b 100644
--- a/hypervisor/common/hypercall.c
+++ b/hypervisor/common/hypercall.c
@@ -788,6 +788,7 @@ hcall_reset_ptdev_intr_info(struct vm *vm, uint16_t
vmid, uint64_t param)
return ret;
}

+#ifdef HV_DEBUG
int32_t hcall_setup_sbuf(struct vm *vm, uint64_t param) {
struct sbuf_setup_param ssp;
@@ -808,6 +809,12 @@ int32_t hcall_setup_sbuf(struct vm *vm, uint64_t
param)

return sbuf_share_setup(ssp.pcpu_id, ssp.sbuf_id, hva); }
+#else
+int32_t hcall_setup_sbuf(__unused struct vm *vm, __unused uint64_t
+param) {
+ return -ENODEV;
+}
+#endif
We also need to do this compile option protection in vmcall.c side for HC_SETUP_SBUF.


The rest is fine. Fixed it and PR with my ack.
Will fix it when PR.


int32_t hcall_get_cpu_pm_state(struct vm *vm, uint64_t cmd, uint64_t
param) { diff --git a/hypervisor/include/arch/x86/per_cpu.h
b/hypervisor/include/arch/x86/per_cpu.h
index 4076e27..758f9c2 100644
--- a/hypervisor/include/arch/x86/per_cpu.h
+++ b/hypervisor/include/arch/x86/per_cpu.h
@@ -19,10 +19,12 @@
#include "arch/x86/guest/instr_emul.h"

struct per_cpu_region {
+#ifdef HV_DEBUG
uint64_t *sbuf[ACRN_SBUF_ID_MAX];
- uint64_t irq_count[NR_IRQS];
uint64_t vmexit_cnt[64];
uint64_t vmexit_time[64];
+#endif
+ uint64_t irq_count[NR_IRQS];
uint64_t softirq_pending;
uint64_t spurious;
uint64_t vmxon_region_pa;
--
2.7.4





Re: [PATCH 5/6] DM USB: xHCI: change flow of creation of virtual USB device

Wu, Xiaoguang
 

On 18-08-13 22:35:32, Yu Wang wrote:
On 18-08-13 16:48:34, Wu, Xiaoguang wrote:
The xHCI emulation greatly depends on the user space library libusb
which is based on the usbfs module in Linux kernel. The libusb will
bind usbfs to physical USB device which makes hardware control over
libusb in user space possible.

The pci_xhci_dev_create is called in pci_xhci_native_usb_dev_conn_cb
which is a callback function triggered by physical USB device plugging.
This function will bind the physical USB device to usbfs in SOS, which
we depend to create the communication between UOS xHCI driver with
physical USB device.

This design will fail if the disconnection happened in the SOS, which
I think it should be re-connection instead of disconnection, right?
xgwu:

ok, will change.
thx.


will bind class driver to the physical USB device instead of usbfs,
hence the libusb device handle in DM is invalid.

Currently when the SOS do the resuming from S3, there are some uncertain
bugs which unbind the usbfs for the USB devices, so the DM will lose
control and can't continue emulation.
Currently, the native S3 will disable the vbus for all xHCI ports and
re-drive during S3 resume. This behavior cause native USB driver unbind
the usbfs and bind to related class driver, then made the DM lost
control and failed to continue emulation.

xguw:

ok, will change.
thx.






To fix this issue, place the pci_xhci_dev_create in the function
pci_xhci_cmd_enable_slot. According to the xHCI spec 4.5.3 Figure 10,
the UOS always send Enable Slot command when a device is attached or
recovered from errors (by Disable Slot command). So every time the SOS
can't resuming normally or some unexpected disconnection happens, this
desigen will always survive by Disable Slot and Enable Slot command
series from UOS xHCI driver.

Signed-off-by: Xiaoguang Wu <xiaoguang.wu@...>
Reviewed-by: Liang Yang <liang3.yang@...>
---
devicemodel/hw/pci/xhci.c | 220 +++++++++++++++++++++++++++++++++-------------
1 file changed, 158 insertions(+), 62 deletions(-)

diff --git a/devicemodel/hw/pci/xhci.c b/devicemodel/hw/pci/xhci.c
index 2df7ce3..579021a 100644
--- a/devicemodel/hw/pci/xhci.c
+++ b/devicemodel/hw/pci/xhci.c
@@ -383,6 +383,7 @@ struct pci_xhci_vdev {
* is stored in native_assign_ports[x][y].
*/
int8_t *native_assign_ports[USB_NATIVE_NUM_BUS];
+ struct usb_native_devinfo *native_assign_info[USB_NATIVE_NUM_BUS];
Can we merge the native_assign_ports and usb_native_devinfo?... Why the
usb_native_devinfo can't include the port info...

xgwu:
change it to:
native_assign_ports -> port_map_tbl
native_assign_info -> native_dev_info

In futurn, should refine it.
thanks.




And I just realized the USB_NATIVE_NUM_BUS... Why it is too huge.. 255
USB buses?...
xgwu:

ok, as discussed, change it to 4.
and change USB_NATIVE_NUM_PORT to 20
thanks.




struct timespec mf_prev_time; /* previous time of accessing MFINDEX */
};

@@ -475,36 +476,21 @@ static struct pci_xhci_option_elem xhci_option_table[] = {
static int
pci_xhci_native_usb_dev_conn_cb(void *hci_data, void *dev_data)
{
- struct pci_xhci_dev_emu *de;
struct pci_xhci_vdev *xdev;
- struct usb_devemu *ue;
struct usb_native_devinfo *di;
int port_start, port_end;
- int slot_start, slot_end;
- int port, slot;
- void *ud;
+ int port;
int intr = 1;
+ int i, j;

xdev = hci_data;
- di = dev_data;

assert(xdev);
assert(dev_data);
assert(xdev->devices);
assert(xdev->slots);

- de = pci_xhci_dev_create(xdev, di->priv_data);
- if (!de) {
- UPRINTF(LFTL, "fail to create device\r\n");
- return -1;
- }
-
- /* find free port and slot for the new usb device */
- ud = de->dev_instance;
- ue = de->dev_ue;
-
- assert(ud);
- assert(ue);
+ di = dev_data;

/* print physical information about new device */
UPRINTF(LDBG, "%04x:%04x %d-%d connecting.\r\n",
@@ -517,43 +503,53 @@ pci_xhci_native_usb_dev_conn_cb(void *hci_data, void *dev_data)
goto errout;
}

+ assert(xdev->native_assign_info[di->bus]);
UPRINTF(LDBG, "%04x:%04x %d-%d belong to this vm.\r\n", di->vid,
di->pid, di->bus, di->port);

- if (di->bcd < 0x300)
+ if (di->bcd < 0x300) {
port_start = xdev->usb2_port_start;
- else
+ port_end = port_start + (XHCI_MAX_DEVS / 2);
+ } else {
port_start = xdev->usb3_port_start;
Please change the port_start/port_end to vport_start/vport_end.
Otherwise, it is easy messed with native ports..
xgwu:

ok, will change it. thanks.





-
- slot_start = 1;
- port_end = port_start + (XHCI_MAX_DEVS / 2);
- slot_end = XHCI_MAX_SLOTS;
+ port_end = port_start + (XHCI_MAX_DEVS / 2);
+ }

/* find free port */
- for (port = port_start; port < port_end; port++)
- if (!xdev->devices[port])
- break;
+ /* FIXME:
+ * Will find a decent way to deal with the relationship among Slot,
+ * Port and Device.
+ */
+ for (port = port_start; port < port_end; port++) {
+ if (xdev->devices[port])
+ continue;
+
+ for (i = 0; i < USB_NATIVE_NUM_BUS; ++i) {
+ if (!xdev->native_assign_ports[i])
+ continue;
+
+ for (j = 0; j < USB_NATIVE_NUM_PORT; ++j)
+ if (xdev->native_assign_ports[i][j] == port)
+ break;
Confused, you are trying to find one free virtual port? Why every native
bus only allow to as one virtual port? Totally confused now.
xgwu:

the code is not good, will change to simpler way.
thanks.




- /* find free slot */
- for (slot = slot_start; slot < slot_end; slot++)
- if (!xdev->slots[slot])
+ if (j < USB_NATIVE_NUM_PORT)
+ break;
+ }
+ if (i >= USB_NATIVE_NUM_BUS)
break;
+ }
We need to rework this loop-loop-loop-if-if-if code... It is too ugly
and confused.. At least, please define one function for it with readily
comprehensible function name.
xgwu:

ok, will change. thanks.




- if (port >= port_end || slot >= slot_end) {
- UPRINTF(LFTL, "no free resource: port %d slot %d\r\n",
- port, slot);
+ if (port >= port_end) {
+ UPRINTF(LFTL, "no free virtual port for native device %d-%d"
+ "\r\n", di->bus, di->port);
goto errout;
}

- /* use index of devices as port number */
- xdev->devices[port] = de;
- xdev->slots[slot] = de;
- xdev->ndevices++;
+ UPRINTF(LDBG, "%X:%X %d-%d is attached to virtual port %d.\r\n",
+ di->vid, di->pid, di->bus, di->port, port);

- pci_xhci_reset_slot(xdev, slot);
- UPRINTF(LDBG, "%X:%X %d-%d locates in slot %d port %d.\r\n",
- di->vid, di->pid, di->bus, di->port,
- slot, port);
+ xdev->native_assign_ports[di->bus][di->port] = port;
+ xdev->native_assign_info[di->bus][di->port] = *di;

/* Trigger port change event for the arriving device */
if (pci_xhci_port_connect(xdev, port, di->speed, intr))
@@ -561,7 +557,6 @@ pci_xhci_native_usb_dev_conn_cb(void *hci_data, void *dev_data)

return 0;
errout:
- pci_xhci_dev_destroy(de);
return -1;
}

@@ -571,8 +566,8 @@ pci_xhci_native_usb_dev_disconn_cb(void *hci_data, void *dev_data)
struct pci_xhci_vdev *xdev;
struct pci_xhci_dev_emu *edev;
struct usb_dev *udev;
- uint8_t port, native_port;
- int intr = 1;
+ uint8_t port, slot, native_port;
+ int i, j, intr = 1;

assert(hci_data);
assert(dev_data);
@@ -601,6 +596,24 @@ pci_xhci_native_usb_dev_disconn_cb(void *hci_data, void *dev_data)
return -1;
}

+ for (slot = 1; slot < XHCI_MAX_SLOTS; ++slot)
+ if (xdev->slots[slot] == edev)
+ break;
+
+ /* FIXME: again, find a better relationship for Slot, Port and Device */
+ for (i = 0; i < USB_NATIVE_NUM_BUS; ++i) {
+ if (!xdev->native_assign_ports[i])
+ continue;
+
+ for (j = 0; j < USB_NATIVE_NUM_PORT; ++j)
+ if (xdev->native_assign_ports[i][j] == port)
+ break;
+
+ if (j < USB_NATIVE_NUM_PORT)
+ break;
+ }
Ditto.

xgwu:

will remove the loop. thx.




+ assert(i < USB_NATIVE_NUM_BUS);
+ xdev->native_assign_ports[i][j] = -1;
Define one macro instead of -1.
xgwu:

ok, will change.thx.




UPRINTF(LDBG, "report virtual port %d status\r\n", port);
if (pci_xhci_port_disconnect(xdev, port, intr)) {
UPRINTF(LFTL, "fail to report event\r\n");
@@ -1405,21 +1418,61 @@ static uint32_t
pci_xhci_cmd_enable_slot(struct pci_xhci_vdev *xdev, uint32_t *slot)
{
struct pci_xhci_dev_emu *dev;
- uint32_t cmderr;
- int i;
+ uint32_t cmderr;
+ struct usb_native_devinfo *di;
+ int i, j, port;

cmderr = XHCI_TRB_ERROR_NO_SLOTS;
- if (xdev->portregs != NULL)
- for (i = 1; i <= XHCI_MAX_SLOTS; i++) {
- dev = XHCI_SLOTDEV_PTR(xdev, i);
- if (dev && dev->dev_slotstate == XHCI_ST_DISABLED) {
- *slot = i;
- dev->dev_slotstate = XHCI_ST_ENABLED;
- cmderr = XHCI_TRB_ERROR_SUCCESS;
- dev->hci.hci_address = i;
- break;
+
+ for (i = 0; i < USB_NATIVE_NUM_BUS; ++i) {
+ if (!xdev->native_assign_ports[i])
+ continue;
+
+ for (j = 0; j < USB_NATIVE_NUM_PORT; ++j) {
+ if (xdev->native_assign_ports[i][j] > 0) {
+ port = xdev->native_assign_ports[i][j];
+ assert(port <= XHCI_MAX_DEVS);
+
+ if (!xdev->devices[port])
+ break;
}
}
+ if (j < USB_NATIVE_NUM_PORT)
+ break;
Ditto

xgwu:


will use a function do this. thanks.






+ }
+
+ if (i >= USB_NATIVE_NUM_BUS) {
+ UPRINTF(LWRN, "unexpected Enable Slot commnad\r\n");
+ return -1;
+ }
+
+ assert(xdev->native_assign_info[i]);
+ di = &xdev->native_assign_info[i][j];
+
+ assert(di->priv_data);
+ dev = pci_xhci_dev_create(xdev, di->priv_data);
+ if (!dev) {
+ UPRINTF(LFTL, "fail to create device\r\n");
+ return -1;
+ }
+
+ port = xdev->native_assign_ports[i][j];
+ assert(port > 0);
+ assert(!xdev->devices[port]);
+
+ xdev->devices[port] = dev;
+ xdev->ndevices++;
+
+ for (i = 1; i <= XHCI_MAX_SLOTS; i++) {
+ if (XHCI_SLOTDEV_PTR(xdev, i) == NULL) {
+ xdev->slots[i] = dev;
+ *slot = i;
+ dev->dev_slotstate = XHCI_ST_ENABLED;
+ cmderr = XHCI_TRB_ERROR_SUCCESS;
+ dev->hci.hci_address = i;
+ break;
+ }
+ }

UPRINTF(LDBG, "enable slot (error=%d) slot %u\r\n",
cmderr != XHCI_TRB_ERROR_SUCCESS, *slot);
@@ -1431,7 +1484,10 @@ static uint32_t
pci_xhci_cmd_disable_slot(struct pci_xhci_vdev *xdev, uint32_t slot)
{
struct pci_xhci_dev_emu *dev;
+ struct usb_devemu *ue;
+ uint8_t native_port, native_bus;
uint32_t cmderr;
+ void *ud;
int i;

UPRINTF(LDBG, "pci_xhci disable slot %u\r\n", slot);
@@ -1454,6 +1510,9 @@ pci_xhci_cmd_disable_slot(struct pci_xhci_vdev *xdev, uint32_t slot)
cmderr = XHCI_TRB_ERROR_SUCCESS;
/* TODO: reset events and endpoints */
}
+ } else {
+ UPRINTF(LDBG, "disable NULL device, slot %d\r\n", slot);
+ goto done;
}

for (i = 1; i <= XHCI_MAX_DEVS; ++i)
@@ -1463,8 +1522,25 @@ pci_xhci_cmd_disable_slot(struct pci_xhci_vdev *xdev, uint32_t slot)
if (i <= XHCI_MAX_DEVS && XHCI_PORTREG_PTR(xdev, i)) {
XHCI_PORTREG_PTR(xdev, i)->portsc &= ~(XHCI_PS_CSC |
XHCI_PS_CCS | XHCI_PS_PED | XHCI_PS_PP);
+
+ ud = dev->dev_instance;
+ ue = dev->dev_ue;
+
+ assert(ud);
+ assert(ue);
+
+ ue->ue_info(ud, USB_INFO_BUS, &native_bus, sizeof(uint8_t));
+ ue->ue_info(ud, USB_INFO_PORT, &native_port, sizeof(uint8_t));
+
xdev->devices[i] = NULL;
xdev->slots[slot] = NULL;
+
+ assert(xdev->native_assign_ports[native_bus]);
+ assert(xdev->native_assign_ports[native_bus][native_port]);
+ UPRINTF(LINF, "disable slot %d for native device %d-%d"
+ "\r\n", slot, native_bus, native_port);
+
+ xdev->native_assign_ports[native_bus][native_port] = -1;
pci_xhci_dev_destroy(dev);
} else
UPRINTF(LWRN, "invalid slot %d\r\n", slot);
@@ -1632,7 +1708,10 @@ pci_xhci_cmd_config_ep(struct pci_xhci_vdev *xdev,
UPRINTF(LDBG, "config_ep slot %u\r\n", slot);

dev = XHCI_SLOTDEV_PTR(xdev, slot);
- assert(dev != NULL);
+ if (dev == NULL) {
+ cmderr = XHCI_TRB_ERROR_SLOT_NOT_ON;
+ goto done;
+ }

if ((trb->dwTrb3 & XHCI_TRB_3_DCEP_BIT) != 0) {
UPRINTF(LDBG, "config_ep - deconfigure ep slot %u\r\n", slot);
@@ -3352,8 +3431,10 @@ errout:
static int
pci_xhci_parse_bus_port(struct pci_xhci_vdev *xdev, char *opts)
{
- int rc = 0, cnt;
+ int rc = 0, cnt, portcnt;
uint32_t port, bus;
+ int8_t *pports;
+ struct usb_native_devinfo *pinfo;

assert(xdev);
assert(opts);
@@ -3372,15 +3453,30 @@ pci_xhci_parse_bus_port(struct pci_xhci_vdev *xdev, char *opts)
goto errout;
}

- if (!xdev->native_assign_ports[bus]) {
- xdev->native_assign_ports[bus] = calloc(USB_NATIVE_NUM_PORT,
- sizeof(int8_t));
- if (!xdev->native_assign_ports[bus]) {
+ pports = xdev->native_assign_ports[bus];
+ pinfo = xdev->native_assign_info[bus];
+
+ /* those two pointers should always be consistant */
+ assert((!pports) == (!pinfo));
+
+ if (!pports) {
+ portcnt = USB_NATIVE_NUM_PORT;
+ pports = calloc(portcnt, sizeof(uint8_t));
+ pinfo = calloc(portcnt, sizeof(struct usb_native_devinfo));
+ if (!pports || !pinfo) {
rc = -3;
- goto errout;
+ goto release_out;
}
+
+ xdev->native_assign_ports[bus] = pports;
+ xdev->native_assign_info[bus] = pinfo;
}
xdev->native_assign_ports[bus][port] = -1;
+ return 0;
+
+release_out:
+ free(pinfo);
+ free(pports);

errout:
if (rc)
--
2.7.4