mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
Merge
This commit is contained in:
commit
ff7c56c82c
11 files changed
+288
-13
No files matched your search
@@ -202,6 +202,7 @@
|
||||
^tools/misc/xenperf$
|
||||
^tools/misc/xenpm$
|
||||
^tools/misc/xen-hvmctx$
|
||||
^tools/misc/xen-lowmemd$
|
||||
^tools/misc/gtraceview$
|
||||
^tools/misc/gtracestat$
|
||||
^tools/misc/xenlockprof$
|
||||
|
||||
@@ -129,10 +129,12 @@
|
||||
/* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx) */
|
||||
#define X86_FEATURE_FSGSBASE 0 /* {RD,WR}{FS,GS}BASE instructions */
|
||||
#define X86_FEATURE_BMI1 3 /* 1st group bit manipulation extensions */
|
||||
#define X86_FEATURE_HLE 4 /* Hardware Lock Elision */
|
||||
#define X86_FEATURE_AVX2 5 /* AVX2 instructions */
|
||||
#define X86_FEATURE_SMEP 7 /* Supervisor Mode Execution Protection */
|
||||
#define X86_FEATURE_BMI2 8 /* 2nd group bit manipulation extensions */
|
||||
#define X86_FEATURE_ERMS 9 /* Enhanced REP MOVSB/STOSB */
|
||||
#define X86_FEATURE_INVPCID 10 /* Invalidate Process Context ID */
|
||||
#define X86_FEATURE_RTM 11 /* Restricted Transactional Memory */
|
||||
|
||||
#endif /* __LIBXC_CPUFEATURE_H */
|
||||
@@ -363,11 +363,13 @@ static void xc_cpuid_hvm_policy(
|
||||
case 0x00000007: /* Intel-defined CPU features */
|
||||
if ( input[1] == 0 ) {
|
||||
regs[1] &= (bitmaskof(X86_FEATURE_BMI1) |
|
||||
bitmaskof(X86_FEATURE_HLE) |
|
||||
bitmaskof(X86_FEATURE_AVX2) |
|
||||
bitmaskof(X86_FEATURE_SMEP) |
|
||||
bitmaskof(X86_FEATURE_BMI2) |
|
||||
bitmaskof(X86_FEATURE_ERMS) |
|
||||
bitmaskof(X86_FEATURE_INVPCID) |
|
||||
bitmaskof(X86_FEATURE_RTM) |
|
||||
bitmaskof(X86_FEATURE_FSGSBASE));
|
||||
} else
|
||||
regs[1] = 0;
|
||||
@@ -496,9 +498,11 @@ static void xc_cpuid_pv_policy(
|
||||
case 0x00000007:
|
||||
if ( input[1] == 0 )
|
||||
regs[1] &= (bitmaskof(X86_FEATURE_BMI1) |
|
||||
bitmaskof(X86_FEATURE_HLE) |
|
||||
bitmaskof(X86_FEATURE_AVX2) |
|
||||
bitmaskof(X86_FEATURE_BMI2) |
|
||||
bitmaskof(X86_FEATURE_ERMS) |
|
||||
bitmaskof(X86_FEATURE_RTM) |
|
||||
bitmaskof(X86_FEATURE_FSGSBASE));
|
||||
else
|
||||
regs[1] = 0;
|
||||
|
||||
+6
-2
@@ -5,11 +5,12 @@ CFLAGS += -Werror
|
||||
|
||||
CFLAGS += $(CFLAGS_libxenctrl)
|
||||
CFLAGS += $(CFLAGS_xeninclude)
|
||||
CFLAGS += $(CFLAGS_libxenstore)
|
||||
|
||||
HDRS = $(wildcard *.h)
|
||||
|
||||
TARGETS-y := xenperf xenpm xen-tmem-list-parse gtraceview gtracestat xenlockprof xenwatchdogd
|
||||
TARGETS-$(CONFIG_X86) += xen-detect xen-hvmctx xen-hvmcrash
|
||||
TARGETS-$(CONFIG_X86) += xen-detect xen-hvmctx xen-hvmcrash xen-lowmemd
|
||||
TARGETS-$(CONFIG_MIGRATE) += xen-hptool
|
||||
TARGETS := $(TARGETS-y)
|
||||
|
||||
@@ -21,7 +22,7 @@ INSTALL_BIN-y := xencons
|
||||
INSTALL_BIN-$(CONFIG_X86) += xen-detect
|
||||
INSTALL_BIN := $(INSTALL_BIN-y)
|
||||
|
||||
INSTALL_SBIN-y := xm xen-bugtool xen-python-path xend xenperf xsview xenpm xen-tmem-list-parse gtraceview gtracestat xenlockprof xenwatchdogd xen-ringwatch
|
||||
INSTALL_SBIN-y := xm xen-bugtool xen-python-path xend xenperf xsview xenpm xen-tmem-list-parse gtraceview gtracestat xenlockprof xenwatchdogd xen-ringwatch xen-lowmemd
|
||||
INSTALL_SBIN-$(CONFIG_X86) += xen-hvmctx xen-hvmcrash
|
||||
INSTALL_SBIN-$(CONFIG_MIGRATE) += xen-hptool
|
||||
INSTALL_SBIN := $(INSTALL_SBIN-y)
|
||||
@@ -70,6 +71,9 @@ xen-hptool: xen-hptool.o
|
||||
xenwatchdogd: xenwatchdogd.o
|
||||
$(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(APPEND_LDFLAGS)
|
||||
|
||||
xen-lowmemd: xen-lowmemd.o
|
||||
$(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(LDLIBS_libxenstore) $(APPEND_LDFLAGS)
|
||||
|
||||
gtraceview: gtraceview.o
|
||||
$(CC) $(LDFLAGS) -o $@ $< $(CURSES_LIBS) $(APPEND_LDFLAGS)
|
||||
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* xen-lowmemd: demo VIRQ_ENOMEM
|
||||
* Andres Lagar-Cavilla (GridCentric Inc.)
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <xenctrl.h>
|
||||
#include <xs.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static evtchn_port_t virq_port = -1;
|
||||
static xc_evtchn *xce_handle = NULL;
|
||||
static xc_interface *xch = NULL;
|
||||
static struct xs_handle *xs_handle = NULL;
|
||||
|
||||
void cleanup(void)
|
||||
{
|
||||
if (virq_port > -1)
|
||||
xc_evtchn_unbind(xce_handle, virq_port);
|
||||
if (xce_handle)
|
||||
xc_evtchn_close(xce_handle);
|
||||
if (xch)
|
||||
xc_interface_close(xch);
|
||||
if (xs_handle)
|
||||
xs_daemon_close(xs_handle);
|
||||
}
|
||||
|
||||
/* Never shrink dom0 below 1 GiB */
|
||||
#define DOM0_FLOOR (1 << 30)
|
||||
#define DOM0_FLOOR_PG ((DOM0_FLOOR) >> 12)
|
||||
|
||||
/* Act if free memory is less than 92 MiB */
|
||||
#define THRESHOLD (92 << 20)
|
||||
#define THRESHOLD_PG ((THRESHOLD) >> 12)
|
||||
|
||||
#define BUFSZ 512
|
||||
void handle_low_mem(void)
|
||||
{
|
||||
xc_dominfo_t dom0_info;
|
||||
xc_physinfo_t info;
|
||||
unsigned long long free_pages, dom0_pages, diff, dom0_target;
|
||||
char data[BUFSZ], error[BUFSZ];
|
||||
|
||||
if (xc_physinfo(xch, &info) < 0)
|
||||
{
|
||||
perror("Getting physinfo failed");
|
||||
return;
|
||||
}
|
||||
|
||||
free_pages = (unsigned long long) info.free_pages;
|
||||
printf("Available free pages: 0x%llx:%llux\n",
|
||||
free_pages, free_pages);
|
||||
|
||||
/* Don't do anything if we have more than the threshold free */
|
||||
if ( free_pages >= THRESHOLD_PG )
|
||||
return;
|
||||
diff = THRESHOLD_PG - free_pages;
|
||||
|
||||
if (xc_domain_getinfo(xch, 0, 1, &dom0_info) < 1)
|
||||
{
|
||||
perror("Failed to get dom0 info");
|
||||
return;
|
||||
}
|
||||
|
||||
dom0_pages = (unsigned long long) dom0_info.nr_pages;
|
||||
printf("Dom0 pages: 0x%llx:%llu\n", dom0_pages, dom0_pages);
|
||||
dom0_target = dom0_pages - diff;
|
||||
if (dom0_target <= DOM0_FLOOR_PG)
|
||||
return;
|
||||
|
||||
printf("Shooting for dom0 target 0x%llx:%llu\n",
|
||||
dom0_target, dom0_target);
|
||||
|
||||
snprintf(data, BUFSZ, "%llu", dom0_target);
|
||||
if (!xs_write(xs_handle, XBT_NULL,
|
||||
"/local/domain/0/memory/target", data, strlen(data)))
|
||||
{
|
||||
snprintf(error, BUFSZ,"Failed to write target %s to xenstore", data);
|
||||
perror(error);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int rc;
|
||||
|
||||
atexit(cleanup);
|
||||
|
||||
xch = xc_interface_open(NULL, NULL, 0);
|
||||
if (xch == NULL)
|
||||
{
|
||||
perror("Failed to open xc interface");
|
||||
return 1;
|
||||
}
|
||||
|
||||
xce_handle = xc_evtchn_open(NULL, 0);
|
||||
if (xce_handle == NULL)
|
||||
{
|
||||
perror("Failed to open evtchn device");
|
||||
return 2;
|
||||
}
|
||||
|
||||
xs_handle = xs_daemon_open();
|
||||
if (xs_handle == NULL)
|
||||
{
|
||||
perror("Failed to open xenstore connection");
|
||||
return 3;
|
||||
}
|
||||
|
||||
if ((rc = xc_evtchn_bind_virq(xce_handle, VIRQ_ENOMEM)) == -1)
|
||||
{
|
||||
perror("Failed to bind to domain exception virq port");
|
||||
return 4;
|
||||
}
|
||||
|
||||
virq_port = rc;
|
||||
|
||||
while(1)
|
||||
{
|
||||
evtchn_port_t port;
|
||||
|
||||
if ((port = xc_evtchn_pending(xce_handle)) == -1)
|
||||
{
|
||||
perror("Failed to listen for pending event channel");
|
||||
return 5;
|
||||
}
|
||||
|
||||
if (port != virq_port)
|
||||
{
|
||||
char data[BUFSZ];
|
||||
snprintf(data, BUFSZ, "Wrong port, got %d expected %d", port, virq_port);
|
||||
perror(data);
|
||||
return 6;
|
||||
}
|
||||
|
||||
if (xc_evtchn_unmask(xce_handle, port) == -1)
|
||||
{
|
||||
perror("Failed to unmask port");
|
||||
return 7;
|
||||
}
|
||||
|
||||
printf("Got a virq kick, time to get work\n");
|
||||
handle_low_mem();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -33,6 +33,8 @@
|
||||
#define vrtc_domain(x) (container_of((x), struct domain, \
|
||||
arch.hvm_domain.pl_time.vrtc))
|
||||
#define vrtc_vcpu(x) (pt_global_vcpu_target(vrtc_domain(x)))
|
||||
#define epoch_year 1900
|
||||
#define get_year(x) (x + epoch_year)
|
||||
|
||||
static void rtc_periodic_cb(struct vcpu *v, void *opaque)
|
||||
{
|
||||
@@ -165,7 +167,7 @@ static void rtc_set_time(RTCState *s)
|
||||
|
||||
ASSERT(spin_is_locked(&s->lock));
|
||||
|
||||
before = mktime(tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
|
||||
before = mktime(get_year(tm->tm_year), tm->tm_mon + 1, tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
|
||||
tm->tm_sec = from_bcd(s, s->hw.cmos_data[RTC_SECONDS]);
|
||||
@@ -179,7 +181,7 @@ static void rtc_set_time(RTCState *s)
|
||||
tm->tm_mon = from_bcd(s, s->hw.cmos_data[RTC_MONTH]) - 1;
|
||||
tm->tm_year = from_bcd(s, s->hw.cmos_data[RTC_YEAR]) + 100;
|
||||
|
||||
after = mktime(tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
|
||||
after = mktime(get_year(tm->tm_year), tm->tm_mon + 1, tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
|
||||
/* We use the guest's setting of the RTC to define the local-time
|
||||
@@ -257,7 +259,7 @@ static void rtc_next_second(RTCState *s)
|
||||
if ( (unsigned)tm->tm_wday >= 7 )
|
||||
tm->tm_wday = 0;
|
||||
days_in_month = get_days_in_month(tm->tm_mon,
|
||||
tm->tm_year + 1900);
|
||||
get_year(tm->tm_year));
|
||||
tm->tm_mday++;
|
||||
if ( tm->tm_mday < 1 )
|
||||
{
|
||||
|
||||
@@ -585,6 +585,8 @@ __gnttab_map_grant_ref(
|
||||
act->start = 0;
|
||||
act->length = PAGE_SIZE;
|
||||
act->is_sub_page = 0;
|
||||
act->trans_domain = rd;
|
||||
act->trans_gref = op->ref;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <xen/perfc.h>
|
||||
#include <xen/numa.h>
|
||||
#include <xen/nodemask.h>
|
||||
#include <xen/event.h>
|
||||
#include <xen/tmem.h>
|
||||
#include <xen/tmem_xen.h>
|
||||
#include <public/sysctl.h>
|
||||
@@ -300,6 +301,107 @@ static unsigned long init_node_heap(int node, unsigned long mfn,
|
||||
return needed;
|
||||
}
|
||||
|
||||
/* Default to 64 MiB */
|
||||
#define DEFAULT_LOW_MEM_VIRQ (((paddr_t) 64) << 20)
|
||||
#define MAX_LOW_MEM_VIRQ (((paddr_t) 1024) << 20)
|
||||
|
||||
static paddr_t __read_mostly opt_low_mem_virq = ((paddr_t) -1);
|
||||
size_param("low_mem_virq_limit", opt_low_mem_virq);
|
||||
|
||||
/* Thresholds to control hysteresis. In pages */
|
||||
/* When memory grows above this threshold, reset hysteresis.
|
||||
* -1 initially to not reset until at least one virq issued. */
|
||||
static unsigned long low_mem_virq_high = -1UL;
|
||||
/* Threshold at which we issue virq */
|
||||
static unsigned long low_mem_virq_th = 0;
|
||||
/* Original threshold after all checks completed */
|
||||
static unsigned long low_mem_virq_orig = 0;
|
||||
/* Order for current threshold */
|
||||
static unsigned int low_mem_virq_th_order = 0;
|
||||
|
||||
/* Perform bootstrapping checks and set bounds */
|
||||
static void __init setup_low_mem_virq(void)
|
||||
{
|
||||
unsigned int order;
|
||||
paddr_t threshold;
|
||||
bool_t halve;
|
||||
|
||||
/* If the user specifies zero, then he/she doesn't want this virq
|
||||
* to ever trigger. */
|
||||
if ( opt_low_mem_virq == 0 )
|
||||
{
|
||||
low_mem_virq_th = -1UL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the user did not specify a knob, remember that */
|
||||
halve = (opt_low_mem_virq == ((paddr_t) -1));
|
||||
threshold = halve ? DEFAULT_LOW_MEM_VIRQ : opt_low_mem_virq;
|
||||
|
||||
/* Dom0 has already been allocated by now. So check we won't be
|
||||
* complaining immediately with whatever's left of the heap. */
|
||||
threshold = min(threshold,
|
||||
((paddr_t) total_avail_pages) << PAGE_SHIFT);
|
||||
|
||||
/* Then, cap to some predefined maximum */
|
||||
threshold = min(threshold, MAX_LOW_MEM_VIRQ);
|
||||
|
||||
/* If the user specified no knob, and we are at the current available
|
||||
* level, halve the threshold. */
|
||||
if ( halve &&
|
||||
(threshold == (((paddr_t) total_avail_pages) << PAGE_SHIFT)) )
|
||||
threshold >>= 1;
|
||||
|
||||
/* Zero? Have to fire immediately */
|
||||
threshold = max(threshold, (paddr_t) PAGE_SIZE);
|
||||
|
||||
/* Threshold bytes -> pages */
|
||||
low_mem_virq_th = threshold >> PAGE_SHIFT;
|
||||
|
||||
/* Next, round the threshold down to the next order */
|
||||
order = get_order_from_pages(low_mem_virq_th);
|
||||
if ( (1UL << order) > low_mem_virq_th )
|
||||
order--;
|
||||
|
||||
/* Set bounds, ready to go */
|
||||
low_mem_virq_th = low_mem_virq_orig = 1UL << order;
|
||||
low_mem_virq_th_order = order;
|
||||
|
||||
printk("Initial low memory virq threshold set at 0x%lx pages.\n",
|
||||
low_mem_virq_th);
|
||||
}
|
||||
|
||||
static void check_low_mem_virq(void)
|
||||
{
|
||||
if ( unlikely(total_avail_pages <= low_mem_virq_th) )
|
||||
{
|
||||
send_global_virq(VIRQ_ENOMEM);
|
||||
|
||||
/* Update thresholds. Next warning will be when we drop below
|
||||
* next order. However, we wait until we grow beyond one
|
||||
* order above us to complain again at the current order */
|
||||
low_mem_virq_high = 1UL << (low_mem_virq_th_order + 1);
|
||||
if ( low_mem_virq_th_order > 0 )
|
||||
low_mem_virq_th_order--;
|
||||
low_mem_virq_th = 1UL << low_mem_virq_th_order;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( unlikely(total_avail_pages >= low_mem_virq_high) )
|
||||
{
|
||||
/* Reset hysteresis. Bring threshold up one order.
|
||||
* If we are back where originally set, set high
|
||||
* threshold to -1 to avoid further growth of
|
||||
* virq threshold. */
|
||||
low_mem_virq_th_order++;
|
||||
low_mem_virq_th = 1UL << low_mem_virq_th_order;
|
||||
if ( low_mem_virq_th == low_mem_virq_orig )
|
||||
low_mem_virq_high = -1UL;
|
||||
else
|
||||
low_mem_virq_high = 1UL << (low_mem_virq_th_order + 2);
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate 2^@order contiguous pages. */
|
||||
static struct page_info *alloc_heap_pages(
|
||||
unsigned int zone_lo, unsigned int zone_hi,
|
||||
@@ -420,6 +522,8 @@ static struct page_info *alloc_heap_pages(
|
||||
total_avail_pages -= request;
|
||||
ASSERT(total_avail_pages >= 0);
|
||||
|
||||
check_low_mem_virq();
|
||||
|
||||
if ( d != NULL )
|
||||
d->last_alloc_node = node;
|
||||
|
||||
@@ -1022,6 +1126,10 @@ void __init scrub_heap_pages(void)
|
||||
}
|
||||
|
||||
printk("done.\n");
|
||||
|
||||
/* Now that the heap is initialized, run checks and set bounds
|
||||
* for the low mem virq algorithm. */
|
||||
setup_low_mem_virq();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -367,6 +367,8 @@ static int iommu_read_log(struct amd_iommu *iommu,
|
||||
u32 tail, head, *entry, tail_offest, head_offset;
|
||||
|
||||
BUG_ON(!iommu || ((log != &iommu->event_log) && (log != &iommu->ppr_log)));
|
||||
|
||||
spin_lock(&log->lock);
|
||||
|
||||
/* make sure there's an entry in the log */
|
||||
tail_offest = ( log == &iommu->event_log ) ?
|
||||
@@ -396,6 +398,8 @@ static int iommu_read_log(struct amd_iommu *iommu,
|
||||
writel(head, iommu->mmio_base + head_offset);
|
||||
}
|
||||
|
||||
spin_unlock(&log->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -618,11 +622,11 @@ static void iommu_check_event_log(struct amd_iommu *iommu)
|
||||
u32 entry;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&iommu->lock, flags);
|
||||
|
||||
iommu_read_log(iommu, &iommu->event_log,
|
||||
sizeof(event_entry_t), parse_event_log_entry);
|
||||
|
||||
spin_lock_irqsave(&iommu->lock, flags);
|
||||
|
||||
/*check event overflow */
|
||||
entry = readl(iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
|
||||
|
||||
@@ -651,14 +655,10 @@ void parse_ppr_log_entry(struct amd_iommu *iommu, u32 entry[])
|
||||
bus = PCI_BUS(device_id);
|
||||
devfn = PCI_DEVFN2(device_id);
|
||||
|
||||
local_irq_enable();
|
||||
|
||||
spin_lock(&pcidevs_lock);
|
||||
pdev = pci_get_pdev(iommu->seg, bus, devfn);
|
||||
spin_unlock(&pcidevs_lock);
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
if ( pdev == NULL )
|
||||
return;
|
||||
|
||||
@@ -672,10 +672,10 @@ static void iommu_check_ppr_log(struct amd_iommu *iommu)
|
||||
u32 entry;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&iommu->lock, flags);
|
||||
|
||||
iommu_read_log(iommu, &iommu->ppr_log,
|
||||
sizeof(ppr_entry_t), parse_ppr_log_entry);
|
||||
|
||||
spin_lock_irqsave(&iommu->lock, flags);
|
||||
|
||||
/*check event overflow */
|
||||
entry = readl(iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
|
||||
@@ -852,6 +852,8 @@ static void * __init allocate_ring_buffer(struct ring_buffer *ring_buf,
|
||||
ring_buf->head = 0;
|
||||
ring_buf->tail = 0;
|
||||
|
||||
spin_lock_init(&ring_buf->lock);
|
||||
|
||||
ring_buf->alloc_size = PAGE_SIZE << get_order_from_bytes(entries *
|
||||
entry_size);
|
||||
ring_buf->entries = ring_buf->alloc_size / entry_size;
|
||||
|
||||
@@ -65,6 +65,7 @@ struct ring_buffer {
|
||||
unsigned long alloc_size;
|
||||
uint32_t tail;
|
||||
uint32_t head;
|
||||
spinlock_t lock; /* protect buffer pointers */
|
||||
};
|
||||
|
||||
typedef struct iommu_cap {
|
||||
|
||||
@@ -158,6 +158,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_pfn_t);
|
||||
#define VIRQ_PCPU_STATE 9 /* G. (DOM0) PCPU state changed */
|
||||
#define VIRQ_MEM_EVENT 10 /* G. (DOM0) A memory event has occured */
|
||||
#define VIRQ_XC_RESERVED 11 /* G. Reserved for XenClient */
|
||||
#define VIRQ_ENOMEM 12 /* G. (DOM0) Low on heap memory */
|
||||
|
||||
/* Architecture-specific VIRQ definitions. */
|
||||
#define VIRQ_ARCH_0 16
|
||||
|
||||