mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
merge with xen-unstable.hg
This commit is contained in:
commit
2bf251e2db
28 files changed
+871
-154
No files matched your search
+26
-6
@@ -240,8 +240,28 @@ static int is_windows_drive(const char *filename)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int bdrv_invalid_protocol_open(BlockDriverState *bs,
|
||||
const char *filename, int flags) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_invalid_protocol = {
|
||||
"invalid_protocol",
|
||||
.bdrv_open = bdrv_invalid_protocol_open,
|
||||
};
|
||||
|
||||
static BlockDriver *find_protocol(const char *filename)
|
||||
{
|
||||
/* Return values:
|
||||
* &bdrv_xxx
|
||||
* filename specifies protocol xxx
|
||||
* caller should use that
|
||||
* NULL filename does not specify any protocol
|
||||
* caller may apply their own default
|
||||
* &bdrv_invalid_protocol filename speciies an unknown protocol
|
||||
* caller should return -ENOENT; or may just try to open with
|
||||
* that bdrv, which always fails that way.
|
||||
*/
|
||||
BlockDriver *drv1;
|
||||
char protocol[128];
|
||||
int len;
|
||||
@@ -254,7 +274,7 @@ static BlockDriver *find_protocol(const char *filename)
|
||||
#endif
|
||||
p = strchr(filename, ':');
|
||||
if (!p)
|
||||
return NULL; /* do not ever guess raw, it is a security problem! */
|
||||
return NULL;
|
||||
len = p - filename;
|
||||
if (len > sizeof(protocol) - 1)
|
||||
len = sizeof(protocol) - 1;
|
||||
@@ -265,7 +285,7 @@ static BlockDriver *find_protocol(const char *filename)
|
||||
!strcmp(drv1->protocol_name, protocol))
|
||||
return drv1;
|
||||
}
|
||||
return NULL;
|
||||
return &bdrv_invalid_protocol;
|
||||
}
|
||||
|
||||
/* XXX: force raw format if block or character device ? It would
|
||||
@@ -295,8 +315,8 @@ static BlockDriver *find_image_format(const char *filename)
|
||||
#endif
|
||||
|
||||
drv = find_protocol(filename);
|
||||
/* no need to test disk image formats for vvfat */
|
||||
if (drv == &bdrv_vvfat)
|
||||
/* no need to test disk image format if the filename told us */
|
||||
if (drv != NULL)
|
||||
return drv;
|
||||
|
||||
ret = bdrv_file_open(&bs, filename, BDRV_O_RDONLY);
|
||||
@@ -390,7 +410,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
|
||||
if (flags & BDRV_O_FILE) {
|
||||
drv = find_protocol(filename);
|
||||
if (!drv)
|
||||
return -ENOENT;
|
||||
drv = &bdrv_raw;
|
||||
} else {
|
||||
if (!drv) {
|
||||
drv = find_image_format(filename);
|
||||
@@ -438,7 +458,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
|
||||
}
|
||||
path_combine(backing_filename, sizeof(backing_filename),
|
||||
filename, bs->backing_file);
|
||||
if (bdrv_open(bs->backing_hd, backing_filename, 0) < 0)
|
||||
if (bdrv_open2(bs->backing_hd, backing_filename, 0, &bdrv_raw) < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
@@ -705,12 +705,13 @@ static void serial_save(QEMUFile *f, void *opaque)
|
||||
qemu_put_8s(f,&s->lsr);
|
||||
qemu_put_8s(f,&s->msr);
|
||||
qemu_put_8s(f,&s->scr);
|
||||
qemu_get_8s(f,&s->fcr);
|
||||
qemu_put_8s(f,&s->fcr);
|
||||
}
|
||||
|
||||
static int serial_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
SerialState *s = opaque;
|
||||
uint8_t fcr = 0;
|
||||
|
||||
if(version_id > 2)
|
||||
return -EINVAL;
|
||||
@@ -729,6 +730,11 @@ static int serial_load(QEMUFile *f, void *opaque, int version_id)
|
||||
qemu_get_8s(f,&s->scr);
|
||||
qemu_get_8s(f,&s->fcr);
|
||||
|
||||
if (version_id >= 2)
|
||||
qemu_get_8s(f,&fcr);
|
||||
|
||||
/* Initialize fcr via setter to perform essential side-effects */
|
||||
serial_ioport_write(s, 0x02, fcr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -502,6 +502,7 @@ static int xenfb_configure_fb(struct xenfb *xenfb, size_t fb_len_lim,
|
||||
fprintf(stderr,
|
||||
"FB: frontend fb size %zu limited to %zu\n",
|
||||
fb_len, fb_len_lim);
|
||||
fb_len = fb_len_lim;
|
||||
}
|
||||
if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
|
||||
fprintf(stderr,
|
||||
|
||||
@@ -260,6 +260,8 @@ void xenstore_parse_domain_config(int hvm_domid)
|
||||
/* autoguess qcow vs qcow2 */
|
||||
} else if (!strcmp(drv,"file") || !strcmp(drv,"phy")) {
|
||||
format = &bdrv_raw;
|
||||
} else if (!strcmp(drv,"phy")) {
|
||||
format = &bdrv_raw;
|
||||
} else {
|
||||
format = bdrv_find_format(drv);
|
||||
if (!format) {
|
||||
@@ -269,7 +271,7 @@ void xenstore_parse_domain_config(int hvm_domid)
|
||||
}
|
||||
}
|
||||
if (bdrv_open2(bs, params, 0 /* snapshot */, format) < 0)
|
||||
fprintf(stderr, "qemu: could not open vbd '%s' or hard disk image '%s' (drv '%s')\n", buf, params, drv ? drv : "?");
|
||||
fprintf(stderr, "qemu: could not open vbd '%s' or hard disk image '%s' (drv '%s' format '%s')\n", buf, params, drv ? drv : "?", format ? format->format_name : "0");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ CTRL_SRCS-y += xc_private.c
|
||||
CTRL_SRCS-y += xc_sedf.c
|
||||
CTRL_SRCS-y += xc_csched.c
|
||||
CTRL_SRCS-y += xc_tbuf.c
|
||||
CTRL_SRCS-y += xc_pm.c
|
||||
ifneq ($(stubdom),y)
|
||||
CTRL_SRCS-y += xc_resume.c
|
||||
endif
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
|
||||
#include <xen/libelf.h>
|
||||
|
||||
#define SUPERPAGE_PFN_SHIFT 9
|
||||
#define SUPERPAGE_NR_PFNS (1UL << SUPERPAGE_PFN_SHIFT)
|
||||
|
||||
#define SCRATCH_PFN 0xFFFFF
|
||||
|
||||
#define SPECIALPAGE_GUARD 0
|
||||
@@ -211,7 +214,7 @@ static int setup_guest(int xc_handle,
|
||||
|
||||
/*
|
||||
* Allocate memory for HVM guest, skipping VGA hole 0xA0000-0xC0000.
|
||||
* We allocate pages in batches of no more than 2048 to ensure that
|
||||
* We allocate pages in batches of no more than 8MB to ensure that
|
||||
* we can be preempted and hence dom0 remains responsive.
|
||||
*/
|
||||
rc = xc_domain_memory_populate_physmap(
|
||||
@@ -219,13 +222,50 @@ static int setup_guest(int xc_handle,
|
||||
cur_pages = 0xc0;
|
||||
while ( (rc == 0) && (nr_pages > cur_pages) )
|
||||
{
|
||||
/* Clip count to maximum 8MB extent. */
|
||||
unsigned long count = nr_pages - cur_pages;
|
||||
if ( count > 2048 )
|
||||
count = 2048;
|
||||
rc = xc_domain_memory_populate_physmap(
|
||||
xc_handle, dom, count, 0, 0, &page_array[cur_pages]);
|
||||
cur_pages += count;
|
||||
|
||||
/* Clip partial superpage extents to superpage boundaries. */
|
||||
if ( ((cur_pages & (SUPERPAGE_NR_PFNS-1)) != 0) &&
|
||||
(count > (-cur_pages & (SUPERPAGE_NR_PFNS-1))) )
|
||||
count = -cur_pages & (SUPERPAGE_NR_PFNS-1); /* clip s.p. tail */
|
||||
else if ( ((count & (SUPERPAGE_NR_PFNS-1)) != 0) &&
|
||||
(count > SUPERPAGE_NR_PFNS) )
|
||||
count &= ~(SUPERPAGE_NR_PFNS - 1); /* clip non-s.p. tail */
|
||||
|
||||
/* Attempt to allocate superpage extents. */
|
||||
if ( ((count | cur_pages) & (SUPERPAGE_NR_PFNS - 1)) == 0 )
|
||||
{
|
||||
long done;
|
||||
xen_pfn_t sp_extents[2048 >> SUPERPAGE_PFN_SHIFT];
|
||||
struct xen_memory_reservation sp_req = {
|
||||
.nr_extents = count >> SUPERPAGE_PFN_SHIFT,
|
||||
.extent_order = SUPERPAGE_PFN_SHIFT,
|
||||
.domid = dom
|
||||
};
|
||||
set_xen_guest_handle(sp_req.extent_start, sp_extents);
|
||||
for ( i = 0; i < sp_req.nr_extents; i++ )
|
||||
sp_extents[i] = page_array[cur_pages+(i<<SUPERPAGE_PFN_SHIFT)];
|
||||
done = xc_memory_op(xc_handle, XENMEM_populate_physmap, &sp_req);
|
||||
if ( done > 0 )
|
||||
{
|
||||
done <<= SUPERPAGE_PFN_SHIFT;
|
||||
cur_pages += done;
|
||||
count -= done;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fall back to 4kB extents. */
|
||||
if ( count != 0 )
|
||||
{
|
||||
rc = xc_domain_memory_populate_physmap(
|
||||
xc_handle, dom, count, 0, 0, &page_array[cur_pages]);
|
||||
cur_pages += count;
|
||||
}
|
||||
}
|
||||
|
||||
if ( rc != 0 )
|
||||
{
|
||||
PERROR("Could not allocate memory for HVM guest.\n");
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/******************************************************************************
|
||||
* xc_pm.c - Libxc API for Xen Power Management (Px/Cx/Tx, etc.) statistic
|
||||
*
|
||||
* Copyright (c) 2008, Liu Jinsong <jinsong.liu@intel.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "xc_private.h"
|
||||
|
||||
int xc_pm_get_max_px(int xc_handle, int cpuid, int *max_px)
|
||||
{
|
||||
DECLARE_SYSCTL;
|
||||
int ret;
|
||||
|
||||
sysctl.cmd = XEN_SYSCTL_get_pmstat;
|
||||
sysctl.u.get_pmstat.type = PMSTAT_get_max_px;
|
||||
sysctl.u.get_pmstat.cpuid = cpuid;
|
||||
ret = xc_sysctl(xc_handle, &sysctl);
|
||||
if ( ret )
|
||||
return ret;
|
||||
|
||||
*max_px = sysctl.u.get_pmstat.u.getpx.total;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xc_pm_get_pxstat(int xc_handle, int cpuid, struct xc_px_stat *pxpt)
|
||||
{
|
||||
DECLARE_SYSCTL;
|
||||
int max_px, ret;
|
||||
|
||||
if ( !pxpt || !(pxpt->trans_pt) || !(pxpt->pt) )
|
||||
return -EINVAL;
|
||||
|
||||
if ( (ret = xc_pm_get_max_px(xc_handle, cpuid, &max_px)) != 0)
|
||||
return ret;
|
||||
|
||||
if ( (ret = lock_pages(pxpt->trans_pt,
|
||||
max_px * max_px * sizeof(uint64_t))) != 0 )
|
||||
return ret;
|
||||
|
||||
if ( (ret = lock_pages(pxpt->pt,
|
||||
max_px * sizeof(struct xc_px_val))) != 0 )
|
||||
{
|
||||
unlock_pages(pxpt->trans_pt, max_px * max_px * sizeof(uint64_t));
|
||||
return ret;
|
||||
}
|
||||
|
||||
sysctl.cmd = XEN_SYSCTL_get_pmstat;
|
||||
sysctl.u.get_pmstat.type = PMSTAT_get_pxstat;
|
||||
sysctl.u.get_pmstat.cpuid = cpuid;
|
||||
set_xen_guest_handle(sysctl.u.get_pmstat.u.getpx.trans_pt, pxpt->trans_pt);
|
||||
set_xen_guest_handle(sysctl.u.get_pmstat.u.getpx.pt,
|
||||
(pm_px_val_t *)pxpt->pt);
|
||||
|
||||
ret = xc_sysctl(xc_handle, &sysctl);
|
||||
if ( ret )
|
||||
{
|
||||
unlock_pages(pxpt->trans_pt, max_px * max_px * sizeof(uint64_t));
|
||||
unlock_pages(pxpt->pt, max_px * sizeof(struct xc_px_val));
|
||||
return ret;
|
||||
}
|
||||
|
||||
pxpt->total = sysctl.u.get_pmstat.u.getpx.total;
|
||||
pxpt->usable = sysctl.u.get_pmstat.u.getpx.usable;
|
||||
pxpt->last = sysctl.u.get_pmstat.u.getpx.last;
|
||||
pxpt->cur = sysctl.u.get_pmstat.u.getpx.cur;
|
||||
|
||||
unlock_pages(pxpt->trans_pt, max_px * max_px * sizeof(uint64_t));
|
||||
unlock_pages(pxpt->pt, max_px * sizeof(struct xc_px_val));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xc_pm_reset_pxstat(int xc_handle, int cpuid)
|
||||
{
|
||||
DECLARE_SYSCTL;
|
||||
|
||||
sysctl.cmd = XEN_SYSCTL_get_pmstat;
|
||||
sysctl.u.get_pmstat.type = PMSTAT_reset_pxstat;
|
||||
sysctl.u.get_pmstat.cpuid = cpuid;
|
||||
|
||||
return xc_sysctl(xc_handle, &sysctl);
|
||||
}
|
||||
@@ -1034,4 +1034,23 @@ void xc_cpuid_to_str(const unsigned int *regs,
|
||||
char **strs);
|
||||
#endif
|
||||
|
||||
struct xc_px_val {
|
||||
uint64_t freq; /* Px core frequency */
|
||||
uint64_t residency; /* Px residency time */
|
||||
uint64_t count; /* Px transition count */
|
||||
};
|
||||
|
||||
struct xc_px_stat {
|
||||
uint8_t total; /* total Px states */
|
||||
uint8_t usable; /* usable Px states */
|
||||
uint8_t last; /* last Px state */
|
||||
uint8_t cur; /* current Px state */
|
||||
uint64_t *trans_pt; /* Px transition table */
|
||||
struct xc_px_val *pt;
|
||||
};
|
||||
|
||||
int xc_pm_get_max_px(int xc_handle, int cpuid, int *max_px);
|
||||
int xc_pm_get_pxstat(int xc_handle, int cpuid, struct xc_px_stat *pxpt);
|
||||
int xc_pm_reset_pxstat(int xc_handle, int cpuid);
|
||||
|
||||
#endif /* XENCTRL_H */
|
||||
@@ -3013,7 +3013,8 @@ class XendDomainInfo:
|
||||
# shortcut if the domain isn't started because
|
||||
# the devcontrollers will have no better information
|
||||
# than XendConfig.
|
||||
if self._stateGet() in (XEN_API_VM_POWER_STATE_HALTED,):
|
||||
if self._stateGet() in (XEN_API_VM_POWER_STATE_HALTED,
|
||||
XEN_API_VM_POWER_STATE_SUSPENDED):
|
||||
if dev_config:
|
||||
return copy.deepcopy(dev_config)
|
||||
return None
|
||||
|
||||
+22
-13
@@ -2424,16 +2424,20 @@ steal_page(struct domain *d, struct page_info *page, unsigned int memflags)
|
||||
|
||||
int
|
||||
guest_physmap_add_page(struct domain *d, unsigned long gpfn,
|
||||
unsigned long mfn)
|
||||
unsigned long mfn, unsigned int page_order)
|
||||
{
|
||||
BUG_ON(!mfn_valid(mfn));
|
||||
BUG_ON(mfn_to_page(mfn)->count_info != (PGC_allocated | 1));
|
||||
set_gpfn_from_mfn(mfn, gpfn);
|
||||
smp_mb();
|
||||
assign_domain_page_replace(d, gpfn << PAGE_SHIFT, mfn,
|
||||
ASSIGN_writable | ASSIGN_pgc_allocated);
|
||||
unsigned long i;
|
||||
|
||||
//BUG_ON(mfn != ((lookup_domain_mpa(d, gpfn << PAGE_SHIFT) & _PFN_MASK) >> PAGE_SHIFT));
|
||||
for (i = 0; i < (1UL << page_order); i++) {
|
||||
BUG_ON(!mfn_valid(mfn));
|
||||
BUG_ON(mfn_to_page(mfn)->count_info != (PGC_allocated | 1));
|
||||
set_gpfn_from_mfn(mfn, gpfn);
|
||||
smp_mb();
|
||||
assign_domain_page_replace(d, gpfn << PAGE_SHIFT, mfn,
|
||||
ASSIGN_writable | ASSIGN_pgc_allocated);
|
||||
mfn++;
|
||||
gpfn++;
|
||||
}
|
||||
|
||||
perfc_incr(guest_physmap_add_page);
|
||||
return 0;
|
||||
@@ -2441,10 +2445,15 @@ guest_physmap_add_page(struct domain *d, unsigned long gpfn,
|
||||
|
||||
void
|
||||
guest_physmap_remove_page(struct domain *d, unsigned long gpfn,
|
||||
unsigned long mfn)
|
||||
unsigned long mfn, unsigned int page_order)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
BUG_ON(mfn == 0);//XXX
|
||||
zap_domain_page_one(d, gpfn << PAGE_SHIFT, 0, mfn);
|
||||
|
||||
for (i = 0; i < (1UL << page_order); i++)
|
||||
zap_domain_page_one(d, (gpfn+i) << PAGE_SHIFT, 0, mfn+i);
|
||||
|
||||
perfc_incr(guest_physmap_remove_page);
|
||||
}
|
||||
|
||||
@@ -2847,7 +2856,7 @@ arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
|
||||
if (prev_mfn && mfn_valid(prev_mfn)) {
|
||||
if (is_xen_heap_mfn(prev_mfn))
|
||||
/* Xen heap frames are simply unhooked from this phys slot. */
|
||||
guest_physmap_remove_page(d, xatp.gpfn, prev_mfn);
|
||||
guest_physmap_remove_page(d, xatp.gpfn, prev_mfn, 0);
|
||||
else
|
||||
/* Normal domain memory is freed, to avoid leaking memory. */
|
||||
guest_remove_page(d, xatp.gpfn);
|
||||
@@ -2856,10 +2865,10 @@ arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
|
||||
/* Unmap from old location, if any. */
|
||||
gpfn = get_gpfn_from_mfn(mfn);
|
||||
if (gpfn != INVALID_M2P_ENTRY)
|
||||
guest_physmap_remove_page(d, gpfn, mfn);
|
||||
guest_physmap_remove_page(d, gpfn, mfn, 0);
|
||||
|
||||
/* Map at new location. */
|
||||
guest_physmap_add_page(d, xatp.gpfn, mfn);
|
||||
guest_physmap_add_page(d, xatp.gpfn, mfn, 0);
|
||||
|
||||
out:
|
||||
domain_unlock(d);
|
||||
|
||||
@@ -2,3 +2,4 @@ subdir-y += cpufreq
|
||||
|
||||
obj-y += boot.o
|
||||
obj-y += power.o suspend.o wakeup_prot.o cpu_idle.o
|
||||
obj-y += pmstat.o
|
||||
@@ -441,17 +441,9 @@ acpi_fadt_parse_sleep_info(struct acpi_table_fadt *fadt)
|
||||
"FACS is shorter than ACPI spec allow: 0x%x",
|
||||
facs->length);
|
||||
|
||||
if ((rsdp->revision < 2) || (facs->length < 32)) {
|
||||
acpi_sinfo.wakeup_vector = facs_pa +
|
||||
offsetof(struct acpi_table_facs,
|
||||
firmware_waking_vector);
|
||||
acpi_sinfo.vector_width = 32;
|
||||
} else {
|
||||
acpi_sinfo.wakeup_vector = facs_pa +
|
||||
offsetof(struct acpi_table_facs,
|
||||
xfirmware_waking_vector);
|
||||
acpi_sinfo.vector_width = 64;
|
||||
}
|
||||
acpi_sinfo.wakeup_vector = facs_pa +
|
||||
offsetof(struct acpi_table_facs, firmware_waking_vector);
|
||||
acpi_sinfo.vector_width = 32;
|
||||
|
||||
printk(KERN_INFO PREFIX
|
||||
" wakeup_vec[%"PRIx64"], vec_size[%x]\n",
|
||||
|
||||
@@ -369,6 +369,8 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
|
||||
if (!check_freqs(cmd.mask, freqs.new, data))
|
||||
return -EAGAIN;
|
||||
|
||||
px_statistic_update(cmd.mask, perf->state, next_perf_state);
|
||||
|
||||
perf->state = next_perf_state;
|
||||
policy->cur = freqs.new;
|
||||
|
||||
@@ -581,9 +583,13 @@ int acpi_cpufreq_init(void)
|
||||
for_each_online_cpu(i) {
|
||||
xen_px_policy[i].cpu = i;
|
||||
|
||||
ret = px_statistic_init(i);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = acpi_cpufreq_cpu_init(&xen_px_policy[i]);
|
||||
if (ret)
|
||||
goto cpufreq_init_out;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* setup ondemand cpufreq */
|
||||
@@ -593,10 +599,10 @@ int acpi_cpufreq_init(void)
|
||||
i = first_cpu(pt[dom]);
|
||||
ret = cpufreq_governor_dbs(&xen_px_policy[i], CPUFREQ_GOV_START);
|
||||
if (ret)
|
||||
goto cpufreq_init_out;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cpufreq_init_out:
|
||||
out:
|
||||
xfree(pt);
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -33,6 +33,83 @@
|
||||
|
||||
struct cpufreq_driver *cpufreq_driver;
|
||||
|
||||
/*********************************************************************
|
||||
* Px STATISTIC INFO *
|
||||
*********************************************************************/
|
||||
|
||||
void px_statistic_update(cpumask_t cpumask, uint8_t from, uint8_t to)
|
||||
{
|
||||
uint32_t i;
|
||||
uint64_t now;
|
||||
|
||||
now = NOW();
|
||||
|
||||
for_each_cpu_mask(i, cpumask) {
|
||||
struct pm_px *pxpt = &px_statistic_data[i];
|
||||
uint32_t statnum = processor_pminfo[i].perf.state_count;
|
||||
|
||||
pxpt->u.last = from;
|
||||
pxpt->u.cur = to;
|
||||
pxpt->u.pt[to].count++;
|
||||
pxpt->u.pt[from].residency += now - pxpt->prev_state_wall;
|
||||
|
||||
(*(pxpt->u.trans_pt + from*statnum + to))++;
|
||||
|
||||
pxpt->prev_state_wall = now;
|
||||
}
|
||||
}
|
||||
|
||||
int px_statistic_init(int cpuid)
|
||||
{
|
||||
uint32_t i, count;
|
||||
struct pm_px *pxpt = &px_statistic_data[cpuid];
|
||||
struct processor_pminfo *pmpt = &processor_pminfo[cpuid];
|
||||
|
||||
count = pmpt->perf.state_count;
|
||||
|
||||
pxpt->u.trans_pt = xmalloc_array(uint64_t, count * count);
|
||||
if (!pxpt->u.trans_pt)
|
||||
return -ENOMEM;
|
||||
|
||||
pxpt->u.pt = xmalloc_array(struct pm_px_val, count);
|
||||
if (!pxpt->u.pt) {
|
||||
xfree(pxpt->u.trans_pt);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(pxpt->u.trans_pt, 0, count * count * (sizeof(uint64_t)));
|
||||
memset(pxpt->u.pt, 0, count * (sizeof(struct pm_px_val)));
|
||||
|
||||
pxpt->u.total = pmpt->perf.state_count;
|
||||
pxpt->u.usable = pmpt->perf.state_count - pmpt->perf.ppc;
|
||||
|
||||
for (i=0; i < pmpt->perf.state_count; i++)
|
||||
pxpt->u.pt[i].freq = pmpt->perf.states[i].core_frequency;
|
||||
|
||||
pxpt->prev_state_wall = NOW();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void px_statistic_reset(int cpuid)
|
||||
{
|
||||
uint32_t i, j, count;
|
||||
struct pm_px *pxpt = &px_statistic_data[cpuid];
|
||||
|
||||
count = processor_pminfo[cpuid].perf.state_count;
|
||||
|
||||
for (i=0; i < count; i++) {
|
||||
pxpt->u.pt[i].residency = 0;
|
||||
pxpt->u.pt[i].count = 0;
|
||||
|
||||
for (j=0; j < count; j++)
|
||||
*(pxpt->u.trans_pt + i*count + j) = 0;
|
||||
}
|
||||
|
||||
pxpt->prev_state_wall = NOW();
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* FREQUENCY TABLE HELPERS *
|
||||
*********************************************************************/
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*****************************************************************************
|
||||
# pmstat.c - Power Management statistic information (Px/Cx/Tx, etc.)
|
||||
#
|
||||
# Copyright (c) 2008, Liu Jinsong <jinsong.liu@intel.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# The full GNU General Public License is included in this distribution in the
|
||||
# file called LICENSE.
|
||||
#
|
||||
*****************************************************************************/
|
||||
|
||||
#include <xen/config.h>
|
||||
#include <xen/lib.h>
|
||||
#include <xen/errno.h>
|
||||
#include <xen/sched.h>
|
||||
#include <xen/event.h>
|
||||
#include <xen/irq.h>
|
||||
#include <xen/iocap.h>
|
||||
#include <xen/compat.h>
|
||||
#include <xen/guest_access.h>
|
||||
#include <asm/current.h>
|
||||
#include <public/xen.h>
|
||||
#include <xen/cpumask.h>
|
||||
#include <asm/processor.h>
|
||||
#include <xen/percpu.h>
|
||||
|
||||
#include <public/sysctl.h>
|
||||
#include <acpi/cpufreq/cpufreq.h>
|
||||
|
||||
struct pm_px px_statistic_data[NR_CPUS];
|
||||
|
||||
int do_get_pm_info(struct xen_sysctl_get_pmstat *op)
|
||||
{
|
||||
int ret = 0;
|
||||
struct pm_px *pxpt = &px_statistic_data[op->cpuid];
|
||||
struct processor_pminfo *pmpt = &processor_pminfo[op->cpuid];
|
||||
|
||||
/* to protect the case when Px was controlled by dom0-kernel */
|
||||
/* or when CPU_FREQ not set in which case ACPI Px objects not parsed */
|
||||
if ( !pmpt->perf.init )
|
||||
return -EINVAL;
|
||||
|
||||
if ( !cpu_online(op->cpuid) )
|
||||
return -EINVAL;
|
||||
|
||||
switch( op->type )
|
||||
{
|
||||
case PMSTAT_get_max_px:
|
||||
{
|
||||
op->u.getpx.total = pmpt->perf.state_count;
|
||||
break;
|
||||
}
|
||||
|
||||
case PMSTAT_get_pxstat:
|
||||
{
|
||||
uint64_t now, ct;
|
||||
|
||||
now = NOW();
|
||||
pxpt->u.usable = pmpt->perf.state_count - pmpt->perf.ppc;
|
||||
pxpt->u.pt[pxpt->u.cur].residency += now - pxpt->prev_state_wall;
|
||||
pxpt->prev_state_wall = now;
|
||||
|
||||
ct = pmpt->perf.state_count;
|
||||
if ( copy_to_guest(op->u.getpx.trans_pt, pxpt->u.trans_pt, ct*ct) )
|
||||
{
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( copy_to_guest(op->u.getpx.pt, pxpt->u.pt, ct) )
|
||||
{
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
op->u.getpx.total = pxpt->u.total;
|
||||
op->u.getpx.usable = pxpt->u.usable;
|
||||
op->u.getpx.last = pxpt->u.last;
|
||||
op->u.getpx.cur = pxpt->u.cur;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PMSTAT_reset_pxstat:
|
||||
{
|
||||
px_statistic_reset(op->cpuid);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
printk("not defined sub-hypercall @ do_get_pm_info\n");
|
||||
ret = -ENOSYS;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
+3
-3
@@ -3297,7 +3297,7 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
|
||||
{
|
||||
if ( is_xen_heap_mfn(prev_mfn) )
|
||||
/* Xen heap frames are simply unhooked from this phys slot. */
|
||||
guest_physmap_remove_page(d, xatp.gpfn, prev_mfn);
|
||||
guest_physmap_remove_page(d, xatp.gpfn, prev_mfn, 0);
|
||||
else
|
||||
/* Normal domain memory is freed, to avoid leaking memory. */
|
||||
guest_remove_page(d, xatp.gpfn);
|
||||
@@ -3306,10 +3306,10 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
|
||||
/* Unmap from old location, if any. */
|
||||
gpfn = get_gpfn_from_mfn(mfn);
|
||||
if ( gpfn != INVALID_M2P_ENTRY )
|
||||
guest_physmap_remove_page(d, gpfn, mfn);
|
||||
guest_physmap_remove_page(d, gpfn, mfn, 0);
|
||||
|
||||
/* Map at new location. */
|
||||
guest_physmap_add_page(d, xatp.gpfn, mfn);
|
||||
guest_physmap_add_page(d, xatp.gpfn, mfn, 0);
|
||||
|
||||
domain_unlock(d);
|
||||
|
||||
|
||||
+150
-42
@@ -20,6 +20,7 @@
|
||||
#include <xen/domain_page.h>
|
||||
#include <xen/sched.h>
|
||||
#include <asm/current.h>
|
||||
#include <asm/paging.h>
|
||||
#include <asm/types.h>
|
||||
#include <asm/domain.h>
|
||||
#include <asm/p2m.h>
|
||||
@@ -46,6 +47,9 @@ static void ept_p2m_type_to_flags(ept_entry_t *entry, p2m_type_t type)
|
||||
}
|
||||
}
|
||||
|
||||
#define GUEST_TABLE_NORMAL_PAGE 1
|
||||
#define GUEST_TABLE_SUPER_PAGE 2
|
||||
|
||||
static int ept_next_level(struct domain *d, bool_t read_only,
|
||||
ept_entry_t **table, unsigned long *gfn_remainder,
|
||||
u32 shift)
|
||||
@@ -54,7 +58,6 @@ static int ept_next_level(struct domain *d, bool_t read_only,
|
||||
u32 index;
|
||||
|
||||
index = *gfn_remainder >> shift;
|
||||
*gfn_remainder &= (1UL << shift) - 1;
|
||||
|
||||
ept_entry = (*table) + index;
|
||||
|
||||
@@ -83,31 +86,53 @@ static int ept_next_level(struct domain *d, bool_t read_only,
|
||||
ept_entry->r = ept_entry->w = ept_entry->x = 1;
|
||||
}
|
||||
|
||||
next = map_domain_page(ept_entry->mfn);
|
||||
unmap_domain_page(*table);
|
||||
*table = next;
|
||||
|
||||
return 1;
|
||||
if ( !ept_entry->sp_avail )
|
||||
{
|
||||
*gfn_remainder &= (1UL << shift) - 1;
|
||||
next = map_domain_page(ept_entry->mfn);
|
||||
unmap_domain_page(*table);
|
||||
*table = next;
|
||||
return GUEST_TABLE_NORMAL_PAGE;
|
||||
}
|
||||
else
|
||||
return GUEST_TABLE_SUPER_PAGE;
|
||||
}
|
||||
|
||||
static int
|
||||
ept_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn, p2m_type_t p2mt)
|
||||
ept_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn,
|
||||
unsigned int order, p2m_type_t p2mt)
|
||||
{
|
||||
ept_entry_t *table =
|
||||
map_domain_page(mfn_x(pagetable_get_mfn(d->arch.phys_table)));
|
||||
unsigned long gfn_remainder = gfn;
|
||||
ept_entry_t *table = NULL;
|
||||
unsigned long gfn_remainder = gfn, offset = 0;
|
||||
ept_entry_t *ept_entry = NULL;
|
||||
u32 index;
|
||||
int i, rv = 0;
|
||||
int i, rv = 0, ret = 0;
|
||||
int walk_level = order / EPT_TABLE_ORDER;
|
||||
|
||||
/* Should check if gfn obeys GAW here */
|
||||
|
||||
for ( i = EPT_DEFAULT_GAW; i > 0; i-- )
|
||||
if ( !ept_next_level(d, 0, &table, &gfn_remainder,
|
||||
i * EPT_TABLE_ORDER) )
|
||||
goto out;
|
||||
if ( order != 0 )
|
||||
if ( (gfn & ((1UL << order) - 1)) )
|
||||
return 1;
|
||||
|
||||
table = map_domain_page(mfn_x(pagetable_get_mfn(d->arch.phys_table)));
|
||||
|
||||
ASSERT(table != NULL);
|
||||
|
||||
for ( i = EPT_DEFAULT_GAW; i > walk_level; i-- )
|
||||
{
|
||||
ret = ept_next_level(d, 0, &table, &gfn_remainder,
|
||||
i * EPT_TABLE_ORDER);
|
||||
if ( !ret )
|
||||
goto out;
|
||||
else if ( ret == GUEST_TABLE_SUPER_PAGE )
|
||||
break;
|
||||
}
|
||||
|
||||
index = gfn_remainder >> ( i ? (i * EPT_TABLE_ORDER): order);
|
||||
walk_level = ( i ? ( i * EPT_TABLE_ORDER) : order) / EPT_TABLE_ORDER;
|
||||
offset = (gfn_remainder & ( ((1 << (i*EPT_TABLE_ORDER)) - 1)));
|
||||
|
||||
index = gfn_remainder;
|
||||
ept_entry = table + index;
|
||||
|
||||
if ( mfn_valid(mfn_x(mfn)) || (p2mt == p2m_mmio_direct) )
|
||||
@@ -117,9 +142,20 @@ ept_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn, p2m_type_t p2mt)
|
||||
d->arch.p2m->max_mapped_pfn = gfn;
|
||||
|
||||
ept_entry->emt = EPT_DEFAULT_MT;
|
||||
ept_entry->sp_avail = 0;
|
||||
ept_entry->sp_avail = walk_level ? 1 : 0;
|
||||
|
||||
if ( ret == GUEST_TABLE_SUPER_PAGE )
|
||||
{
|
||||
ept_entry->mfn = mfn_x(mfn) - offset;
|
||||
if ( ept_entry->avail1 == p2m_ram_logdirty &&
|
||||
p2mt == p2m_ram_rw )
|
||||
for ( i = 0; i < 512; i++ )
|
||||
paging_mark_dirty(d, mfn_x(mfn)-offset+i);
|
||||
}
|
||||
else
|
||||
ept_entry->mfn = mfn_x(mfn);
|
||||
|
||||
ept_entry->avail1 = p2mt;
|
||||
ept_entry->mfn = mfn_x(mfn);
|
||||
ept_entry->rsvd = 0;
|
||||
ept_entry->avail2 = 0;
|
||||
/* last step */
|
||||
@@ -132,14 +168,42 @@ ept_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn, p2m_type_t p2mt)
|
||||
/* Success */
|
||||
rv = 1;
|
||||
|
||||
out:
|
||||
out:
|
||||
unmap_domain_page(table);
|
||||
|
||||
ept_sync_domain(d);
|
||||
|
||||
/* Now the p2m table is not shared with vt-d page table */
|
||||
|
||||
if ( iommu_enabled && is_hvm_domain(d) )
|
||||
{
|
||||
if ( p2mt == p2m_ram_rw )
|
||||
{
|
||||
if ( ret == GUEST_TABLE_SUPER_PAGE )
|
||||
{
|
||||
for ( i = 0; i < 512; i++ )
|
||||
iommu_map_page(d, gfn-offset+i, mfn_x(mfn)-offset+i);
|
||||
}
|
||||
else if ( ret )
|
||||
iommu_map_page(d, gfn, mfn_x(mfn));
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ret == GUEST_TABLE_SUPER_PAGE )
|
||||
{
|
||||
for ( i = 0; i < 512; i++ )
|
||||
iommu_unmap_page(d, gfn-offset+i);
|
||||
}
|
||||
else if ( ret )
|
||||
iommu_unmap_page(d, gfn);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef P2M_SHARE_WITH_VTD_PAGE_TABLE
|
||||
/* If p2m table is shared with vtd page-table. */
|
||||
if ( iommu_enabled && is_hvm_domain(d) && (p2mt == p2m_mmio_direct) )
|
||||
iommu_flush(d, gfn, (u64*)ept_entry);
|
||||
#endif
|
||||
|
||||
return rv;
|
||||
}
|
||||
@@ -152,7 +216,7 @@ static mfn_t ept_get_entry(struct domain *d, unsigned long gfn, p2m_type_t *t)
|
||||
unsigned long gfn_remainder = gfn;
|
||||
ept_entry_t *ept_entry;
|
||||
u32 index;
|
||||
int i;
|
||||
int i, ret=0;
|
||||
mfn_t mfn = _mfn(INVALID_MFN);
|
||||
|
||||
*t = p2m_mmio_dm;
|
||||
@@ -164,17 +228,31 @@ static mfn_t ept_get_entry(struct domain *d, unsigned long gfn, p2m_type_t *t)
|
||||
/* Should check if gfn obeys GAW here. */
|
||||
|
||||
for ( i = EPT_DEFAULT_GAW; i > 0; i-- )
|
||||
if ( !ept_next_level(d, 1, &table, &gfn_remainder,
|
||||
i * EPT_TABLE_ORDER) )
|
||||
{
|
||||
ret = ept_next_level(d, 1, &table, &gfn_remainder,
|
||||
i * EPT_TABLE_ORDER);
|
||||
if ( !ret )
|
||||
goto out;
|
||||
else if ( ret == GUEST_TABLE_SUPER_PAGE )
|
||||
break;
|
||||
}
|
||||
|
||||
index = gfn_remainder;
|
||||
index = gfn_remainder >> ( i * EPT_TABLE_ORDER);
|
||||
ept_entry = table + index;
|
||||
|
||||
if ( ept_entry->avail1 != p2m_invalid )
|
||||
{
|
||||
*t = ept_entry->avail1;
|
||||
mfn = _mfn(ept_entry->mfn);
|
||||
if ( i )
|
||||
{
|
||||
/* we may meet super pages, and to split into 4k pages
|
||||
* to emulate p2m table
|
||||
*/
|
||||
unsigned long split_mfn =
|
||||
mfn_x(mfn) + (gfn_remainder & ( ((1 << (i*EPT_TABLE_ORDER)) - 1 )));
|
||||
mfn = _mfn(split_mfn);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -205,33 +283,63 @@ static void ept_change_entry_type_global(struct domain *d,
|
||||
l4e = map_domain_page(mfn_x(pagetable_get_mfn(d->arch.phys_table)));
|
||||
for (i4 = 0; i4 < EPT_PAGETABLE_ENTRIES; i4++ )
|
||||
{
|
||||
if ( !l4e[i4].epte || l4e[i4].sp_avail )
|
||||
if ( !l4e[i4].epte )
|
||||
continue;
|
||||
l3e = map_domain_page(l4e[i4].mfn);
|
||||
for ( i3 = 0; i3 < EPT_PAGETABLE_ENTRIES; i3++ )
|
||||
if ( !l4e[i4].sp_avail )
|
||||
{
|
||||
if ( !l3e[i3].epte || l3e[i3].sp_avail )
|
||||
continue;
|
||||
l2e = map_domain_page(l3e[i3].mfn);
|
||||
for ( i2 = 0; i2 < EPT_PAGETABLE_ENTRIES; i2++ )
|
||||
l3e = map_domain_page(l4e[i4].mfn);
|
||||
for ( i3 = 0; i3 < EPT_PAGETABLE_ENTRIES; i3++ )
|
||||
{
|
||||
if ( !l2e[i2].epte || l2e[i2].sp_avail )
|
||||
if ( !l3e[i3].epte )
|
||||
continue;
|
||||
l1e = map_domain_page(l2e[i2].mfn);
|
||||
for ( i1 = 0; i1 < EPT_PAGETABLE_ENTRIES; i1++ )
|
||||
if ( !l3e[i3].sp_avail )
|
||||
{
|
||||
if ( !l1e[i1].epte )
|
||||
continue;
|
||||
if ( l1e[i1].avail1 != ot )
|
||||
continue;
|
||||
l1e[i1].avail1 = nt;
|
||||
ept_p2m_type_to_flags(l1e+i1, nt);
|
||||
l2e = map_domain_page(l3e[i3].mfn);
|
||||
for ( i2 = 0; i2 < EPT_PAGETABLE_ENTRIES; i2++ )
|
||||
{
|
||||
if ( !l2e[i2].epte )
|
||||
continue;
|
||||
if ( !l2e[i2].sp_avail )
|
||||
{
|
||||
l1e = map_domain_page(l2e[i2].mfn);
|
||||
for ( i1 = 0; i1 < EPT_PAGETABLE_ENTRIES; i1++ )
|
||||
{
|
||||
if ( !l1e[i1].epte )
|
||||
continue;
|
||||
if ( l1e[i1].avail1 != ot )
|
||||
continue;
|
||||
l1e[i1].avail1 = nt;
|
||||
ept_p2m_type_to_flags(l1e+i1, nt);
|
||||
}
|
||||
unmap_domain_page(l1e);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( l2e[i2].avail1 != ot )
|
||||
continue;
|
||||
l2e[i2].avail1 = nt;
|
||||
ept_p2m_type_to_flags(l2e+i2, nt);
|
||||
}
|
||||
}
|
||||
unmap_domain_page(l2e);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( l3e[i3].avail1 != ot )
|
||||
continue;
|
||||
l3e[i3].avail1 = nt;
|
||||
ept_p2m_type_to_flags(l3e+i3, nt);
|
||||
}
|
||||
unmap_domain_page(l1e);
|
||||
}
|
||||
unmap_domain_page(l2e);
|
||||
unmap_domain_page(l3e);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( l4e[i4].avail1 != ot )
|
||||
continue;
|
||||
l4e[i4].avail1 = nt;
|
||||
ept_p2m_type_to_flags(l4e+i4, nt);
|
||||
}
|
||||
unmap_domain_page(l3e);
|
||||
}
|
||||
unmap_domain_page(l4e);
|
||||
|
||||
|
||||
+195
-48
@@ -151,9 +151,11 @@ p2m_next_level(struct domain *d, mfn_t *table_mfn, void **table,
|
||||
unsigned long *gfn_remainder, unsigned long gfn, u32 shift,
|
||||
u32 max, unsigned long type)
|
||||
{
|
||||
l1_pgentry_t *l1_entry;
|
||||
l1_pgentry_t *p2m_entry;
|
||||
l1_pgentry_t new_entry;
|
||||
void *next;
|
||||
int i;
|
||||
ASSERT(d->arch.p2m->alloc_page);
|
||||
|
||||
if ( !(p2m_entry = p2m_find_entry(*table, gfn_remainder, gfn,
|
||||
@@ -194,6 +196,44 @@ p2m_next_level(struct domain *d, mfn_t *table_mfn, void **table,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(l1e_get_flags(*p2m_entry) & _PAGE_PRESENT);
|
||||
|
||||
/* split single large page into 4KB page in P2M table */
|
||||
if ( type == PGT_l1_page_table && (l1e_get_flags(*p2m_entry) & _PAGE_PSE) )
|
||||
{
|
||||
unsigned long flags, pfn;
|
||||
struct page_info *pg = d->arch.p2m->alloc_page(d);
|
||||
if ( pg == NULL )
|
||||
return 0;
|
||||
list_add_tail(&pg->list, &d->arch.p2m->pages);
|
||||
pg->u.inuse.type_info = PGT_l1_page_table | 1 | PGT_validated;
|
||||
pg->count_info = 1;
|
||||
|
||||
/* New splintered mappings inherit the flags of the old superpage,
|
||||
* with a little reorganisation for the _PAGE_PSE_PAT bit. */
|
||||
flags = l1e_get_flags(*p2m_entry);
|
||||
pfn = l1e_get_pfn(*p2m_entry);
|
||||
if ( pfn & 1 ) /* ==> _PAGE_PSE_PAT was set */
|
||||
pfn -= 1; /* Clear it; _PAGE_PSE becomes _PAGE_PAT */
|
||||
else
|
||||
flags &= ~_PAGE_PSE; /* Clear _PAGE_PSE (== _PAGE_PAT) */
|
||||
|
||||
l1_entry = map_domain_page(mfn_x(page_to_mfn(pg)));
|
||||
for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )
|
||||
{
|
||||
new_entry = l1e_from_pfn(pfn + i, flags);
|
||||
paging_write_p2m_entry(d, gfn,
|
||||
l1_entry+i, *table_mfn, new_entry, 1);
|
||||
}
|
||||
unmap_domain_page(l1_entry);
|
||||
|
||||
new_entry = l1e_from_pfn(mfn_x(page_to_mfn(pg)),
|
||||
__PAGE_HYPERVISOR|_PAGE_USER);
|
||||
paging_write_p2m_entry(d, gfn,
|
||||
p2m_entry, *table_mfn, new_entry, 2);
|
||||
}
|
||||
|
||||
*table_mfn = _mfn(l1e_get_pfn(*p2m_entry));
|
||||
next = map_domain_page(mfn_x(*table_mfn));
|
||||
unmap_domain_page(*table);
|
||||
@@ -204,7 +244,8 @@ p2m_next_level(struct domain *d, mfn_t *table_mfn, void **table,
|
||||
|
||||
// Returns 0 on error (out of memory)
|
||||
static int
|
||||
p2m_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn, p2m_type_t p2mt)
|
||||
p2m_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn,
|
||||
unsigned int page_order, p2m_type_t p2mt)
|
||||
{
|
||||
// XXX -- this might be able to be faster iff current->domain == d
|
||||
mfn_t table_mfn = pagetable_get_mfn(d->arch.phys_table);
|
||||
@@ -212,6 +253,7 @@ p2m_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn, p2m_type_t p2mt)
|
||||
unsigned long gfn_remainder = gfn;
|
||||
l1_pgentry_t *p2m_entry;
|
||||
l1_pgentry_t entry_content;
|
||||
l2_pgentry_t l2e_content;
|
||||
int rv=0;
|
||||
|
||||
#if CONFIG_PAGING_LEVELS >= 4
|
||||
@@ -235,27 +277,54 @@ p2m_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn, p2m_type_t p2mt)
|
||||
PGT_l2_page_table) )
|
||||
goto out;
|
||||
|
||||
if ( !p2m_next_level(d, &table_mfn, &table, &gfn_remainder, gfn,
|
||||
L2_PAGETABLE_SHIFT - PAGE_SHIFT,
|
||||
L2_PAGETABLE_ENTRIES, PGT_l1_page_table) )
|
||||
goto out;
|
||||
if ( page_order == 0 )
|
||||
{
|
||||
if ( !p2m_next_level(d, &table_mfn, &table, &gfn_remainder, gfn,
|
||||
L2_PAGETABLE_SHIFT - PAGE_SHIFT,
|
||||
L2_PAGETABLE_ENTRIES, PGT_l1_page_table) )
|
||||
goto out;
|
||||
|
||||
p2m_entry = p2m_find_entry(table, &gfn_remainder, gfn,
|
||||
0, L1_PAGETABLE_ENTRIES);
|
||||
ASSERT(p2m_entry);
|
||||
p2m_entry = p2m_find_entry(table, &gfn_remainder, gfn,
|
||||
0, L1_PAGETABLE_ENTRIES);
|
||||
ASSERT(p2m_entry);
|
||||
|
||||
if ( mfn_valid(mfn) || (p2mt == p2m_mmio_direct) )
|
||||
entry_content = l1e_from_pfn(mfn_x(mfn), p2m_type_to_flags(p2mt));
|
||||
else
|
||||
entry_content = l1e_empty();
|
||||
|
||||
/* level 1 entry */
|
||||
paging_write_p2m_entry(d, gfn, p2m_entry, table_mfn, entry_content, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
p2m_entry = p2m_find_entry(table, &gfn_remainder, gfn,
|
||||
L2_PAGETABLE_SHIFT - PAGE_SHIFT,
|
||||
L2_PAGETABLE_ENTRIES);
|
||||
ASSERT(p2m_entry);
|
||||
|
||||
if ( (l1e_get_flags(*p2m_entry) & _PAGE_PRESENT) &&
|
||||
!(l1e_get_flags(*p2m_entry) & _PAGE_PSE) )
|
||||
{
|
||||
P2M_ERROR("configure P2M table 4KB L2 entry with large page\n");
|
||||
domain_crash(d);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ( mfn_valid(mfn) )
|
||||
l2e_content = l2e_from_pfn(mfn_x(mfn),
|
||||
p2m_type_to_flags(p2mt) | _PAGE_PSE);
|
||||
else
|
||||
l2e_content = l2e_empty();
|
||||
|
||||
entry_content.l1 = l2e_content.l2;
|
||||
paging_write_p2m_entry(d, gfn, p2m_entry, table_mfn, entry_content, 2);
|
||||
}
|
||||
|
||||
/* Track the highest gfn for which we have ever had a valid mapping */
|
||||
if ( mfn_valid(mfn) && (gfn > d->arch.p2m->max_mapped_pfn) )
|
||||
d->arch.p2m->max_mapped_pfn = gfn;
|
||||
|
||||
if ( mfn_valid(mfn) || (p2mt == p2m_mmio_direct) )
|
||||
entry_content = l1e_from_pfn(mfn_x(mfn), p2m_type_to_flags(p2mt));
|
||||
else
|
||||
entry_content = l1e_empty();
|
||||
|
||||
/* level 1 entry */
|
||||
paging_write_p2m_entry(d, gfn, p2m_entry, table_mfn, entry_content, 1);
|
||||
|
||||
if ( iommu_enabled && is_hvm_domain(d) )
|
||||
{
|
||||
if ( p2mt == p2m_ram_rw )
|
||||
@@ -335,6 +404,16 @@ p2m_gfn_to_mfn(struct domain *d, unsigned long gfn, p2m_type_t *t)
|
||||
unmap_domain_page(l2e);
|
||||
return _mfn(INVALID_MFN);
|
||||
}
|
||||
else if ( (l2e_get_flags(*l2e) & _PAGE_PSE) )
|
||||
{
|
||||
mfn = _mfn(l2e_get_pfn(*l2e) + l1_table_offset(addr));
|
||||
*t = p2m_flags_to_type(l2e_get_flags(*l2e));
|
||||
unmap_domain_page(l2e);
|
||||
|
||||
ASSERT(mfn_valid(mfn) || !p2m_is_ram(*t));
|
||||
return (p2m_is_valid(*t)) ? mfn : _mfn(INVALID_MFN);
|
||||
}
|
||||
|
||||
mfn = _mfn(l2e_get_pfn(*l2e));
|
||||
unmap_domain_page(l2e);
|
||||
|
||||
@@ -358,6 +437,7 @@ static mfn_t p2m_gfn_to_mfn_current(unsigned long gfn, p2m_type_t *t)
|
||||
{
|
||||
mfn_t mfn = _mfn(INVALID_MFN);
|
||||
p2m_type_t p2mt = p2m_mmio_dm;
|
||||
paddr_t addr = ((paddr_t)gfn) << PAGE_SHIFT;
|
||||
/* XXX This is for compatibility with the old model, where anything not
|
||||
* XXX marked as RAM was considered to be emulated MMIO space.
|
||||
* XXX Once we start explicitly registering MMIO regions in the p2m
|
||||
@@ -366,26 +446,45 @@ static mfn_t p2m_gfn_to_mfn_current(unsigned long gfn, p2m_type_t *t)
|
||||
if ( gfn <= current->domain->arch.p2m->max_mapped_pfn )
|
||||
{
|
||||
l1_pgentry_t l1e = l1e_empty();
|
||||
l2_pgentry_t l2e = l2e_empty();
|
||||
int ret;
|
||||
|
||||
ASSERT(gfn < (RO_MPT_VIRT_END - RO_MPT_VIRT_START)
|
||||
/ sizeof(l1_pgentry_t));
|
||||
|
||||
/* Need to __copy_from_user because the p2m is sparse and this
|
||||
* part might not exist */
|
||||
ret = __copy_from_user(&l1e,
|
||||
&phys_to_machine_mapping[gfn],
|
||||
sizeof(l1e));
|
||||
|
||||
if ( ret == 0 ) {
|
||||
p2mt = p2m_flags_to_type(l1e_get_flags(l1e));
|
||||
ASSERT(l1e_get_pfn(l1e) != INVALID_MFN || !p2m_is_ram(p2mt));
|
||||
ret = __copy_from_user(&l2e,
|
||||
&__linear_l1_table[l1_linear_offset(RO_MPT_VIRT_START) + l2_linear_offset(addr)],
|
||||
sizeof(l2e));
|
||||
|
||||
if ( (ret == 0) && (l2e_get_flags(l2e) & _PAGE_PRESENT) &&
|
||||
(l2e_get_flags(l2e) & _PAGE_PSE) )
|
||||
{
|
||||
p2mt = p2m_flags_to_type(l2e_get_flags(l2e));
|
||||
ASSERT(l2e_get_pfn(l2e) != INVALID_MFN || !p2m_is_ram(p2mt));
|
||||
if ( p2m_is_valid(p2mt) )
|
||||
mfn = _mfn(l1e_get_pfn(l1e));
|
||||
else
|
||||
/* XXX see above */
|
||||
mfn = _mfn(l2e_get_pfn(l2e) + l1_table_offset(addr));
|
||||
else
|
||||
p2mt = p2m_mmio_dm;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Need to __copy_from_user because the p2m is sparse and this
|
||||
* part might not exist */
|
||||
ret = __copy_from_user(&l1e,
|
||||
&phys_to_machine_mapping[gfn],
|
||||
sizeof(l1e));
|
||||
|
||||
if ( ret == 0 ) {
|
||||
p2mt = p2m_flags_to_type(l1e_get_flags(l1e));
|
||||
ASSERT(l1e_get_pfn(l1e) != INVALID_MFN || !p2m_is_ram(p2mt));
|
||||
if ( p2m_is_valid(p2mt) )
|
||||
mfn = _mfn(l1e_get_pfn(l1e));
|
||||
else
|
||||
/* XXX see above */
|
||||
p2mt = p2m_mmio_dm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*t = p2mt;
|
||||
@@ -430,9 +529,10 @@ void p2m_change_entry_type_global(struct domain *d,
|
||||
}
|
||||
|
||||
static inline
|
||||
int set_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn, p2m_type_t p2mt)
|
||||
int set_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn,
|
||||
unsigned int page_order, p2m_type_t p2mt)
|
||||
{
|
||||
return d->arch.p2m->set_entry(d, gfn, mfn, p2mt);
|
||||
return d->arch.p2m->set_entry(d, gfn, mfn, page_order, p2mt);
|
||||
}
|
||||
|
||||
// Allocate a new p2m table for a domain.
|
||||
@@ -493,7 +593,8 @@ int p2m_alloc_table(struct domain *d,
|
||||
P2M_PRINTK("populating p2m table\n");
|
||||
|
||||
/* Initialise physmap tables for slot zero. Other code assumes this. */
|
||||
if ( !set_p2m_entry(d, 0, _mfn(INVALID_MFN), p2m_invalid) )
|
||||
if ( !set_p2m_entry(d, 0, _mfn(INVALID_MFN), 0,
|
||||
p2m_invalid) )
|
||||
goto error;
|
||||
|
||||
/* Copy all existing mappings from the page list and m2p */
|
||||
@@ -512,7 +613,7 @@ int p2m_alloc_table(struct domain *d,
|
||||
(gfn != 0x55555555L)
|
||||
#endif
|
||||
&& gfn != INVALID_M2P_ENTRY
|
||||
&& !set_p2m_entry(d, gfn, mfn, p2m_ram_rw) )
|
||||
&& !set_p2m_entry(d, gfn, mfn, 0, p2m_ram_rw) )
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -688,6 +789,28 @@ static void audit_p2m(struct domain *d)
|
||||
gfn += 1 << (L2_PAGETABLE_SHIFT - PAGE_SHIFT);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check for super page */
|
||||
if ( l2e_get_flags(l2e[i2]) & _PAGE_PSE )
|
||||
{
|
||||
mfn = l2e_get_pfn(l2e[i2]);
|
||||
ASSERT(mfn_valid(_mfn(mfn)));
|
||||
for ( i1 = 0; i1 < L1_PAGETABLE_ENTRIES; i1++)
|
||||
{
|
||||
m2pfn = get_gpfn_from_mfn(mfn+i1);
|
||||
if ( m2pfn != (gfn + i) )
|
||||
{
|
||||
pmbad++;
|
||||
P2M_PRINTK("mismatch: gfn %#lx -> mfn %#lx"
|
||||
" -> gfn %#lx\n", gfn+i, mfn+i,
|
||||
m2pfn);
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
gfn += 1 << (L2_PAGETABLE_SHIFT - PAGE_SHIFT);
|
||||
continue;
|
||||
}
|
||||
|
||||
l1e = map_domain_page(mfn_x(_mfn(l2e_get_pfn(l2e[i2]))));
|
||||
|
||||
for ( i1 = 0; i1 < L1_PAGETABLE_ENTRIES; i1++, gfn++ )
|
||||
@@ -737,32 +860,38 @@ static void audit_p2m(struct domain *d)
|
||||
|
||||
|
||||
static void
|
||||
p2m_remove_page(struct domain *d, unsigned long gfn, unsigned long mfn)
|
||||
p2m_remove_page(struct domain *d, unsigned long gfn, unsigned long mfn,
|
||||
unsigned int page_order)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
if ( !paging_mode_translate(d) )
|
||||
return;
|
||||
|
||||
P2M_DEBUG("removing gfn=%#lx mfn=%#lx\n", gfn, mfn);
|
||||
|
||||
set_p2m_entry(d, gfn, _mfn(INVALID_MFN), p2m_invalid);
|
||||
set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY);
|
||||
set_p2m_entry(d, gfn, _mfn(INVALID_MFN), page_order, p2m_invalid);
|
||||
for ( i = 0; i < (1UL << page_order); i++ )
|
||||
set_gpfn_from_mfn(mfn+i, INVALID_M2P_ENTRY);
|
||||
}
|
||||
|
||||
void
|
||||
guest_physmap_remove_page(struct domain *d, unsigned long gfn,
|
||||
unsigned long mfn)
|
||||
unsigned long mfn, unsigned int page_order)
|
||||
{
|
||||
p2m_lock(d->arch.p2m);
|
||||
audit_p2m(d);
|
||||
p2m_remove_page(d, gfn, mfn);
|
||||
p2m_remove_page(d, gfn, mfn, page_order);
|
||||
audit_p2m(d);
|
||||
p2m_unlock(d->arch.p2m);
|
||||
}
|
||||
|
||||
int
|
||||
guest_physmap_add_entry(struct domain *d, unsigned long gfn,
|
||||
unsigned long mfn, p2m_type_t t)
|
||||
unsigned long mfn, unsigned int page_order,
|
||||
p2m_type_t t)
|
||||
{
|
||||
unsigned long ogfn;
|
||||
unsigned long i, ogfn;
|
||||
p2m_type_t ot;
|
||||
mfn_t omfn;
|
||||
int rc = 0;
|
||||
@@ -795,7 +924,8 @@ guest_physmap_add_entry(struct domain *d, unsigned long gfn,
|
||||
if ( p2m_is_ram(ot) )
|
||||
{
|
||||
ASSERT(mfn_valid(omfn));
|
||||
set_gpfn_from_mfn(mfn_x(omfn), INVALID_M2P_ENTRY);
|
||||
for ( i = 0; i < (1UL << page_order); i++ )
|
||||
set_gpfn_from_mfn(mfn_x(omfn)+i, INVALID_M2P_ENTRY);
|
||||
}
|
||||
|
||||
ogfn = mfn_to_gfn(d, _mfn(mfn));
|
||||
@@ -818,21 +948,23 @@ guest_physmap_add_entry(struct domain *d, unsigned long gfn,
|
||||
P2M_DEBUG("old gfn=%#lx -> mfn %#lx\n",
|
||||
ogfn , mfn_x(omfn));
|
||||
if ( mfn_x(omfn) == mfn )
|
||||
p2m_remove_page(d, ogfn, mfn);
|
||||
p2m_remove_page(d, ogfn, mfn, page_order);
|
||||
}
|
||||
}
|
||||
|
||||
if ( mfn_valid(_mfn(mfn)) )
|
||||
{
|
||||
if ( !set_p2m_entry(d, gfn, _mfn(mfn), t) )
|
||||
if ( !set_p2m_entry(d, gfn, _mfn(mfn), page_order, t) )
|
||||
rc = -EINVAL;
|
||||
set_gpfn_from_mfn(mfn, gfn);
|
||||
for ( i = 0; i < (1UL << page_order); i++ )
|
||||
set_gpfn_from_mfn(mfn+i, gfn+i);
|
||||
}
|
||||
else
|
||||
{
|
||||
gdprintk(XENLOG_WARNING, "Adding bad mfn to p2m map (%#lx -> %#lx)\n",
|
||||
gfn, mfn);
|
||||
if ( !set_p2m_entry(d, gfn, _mfn(INVALID_MFN), p2m_invalid) )
|
||||
if ( !set_p2m_entry(d, gfn, _mfn(INVALID_MFN), page_order,
|
||||
p2m_invalid) )
|
||||
rc = -EINVAL;
|
||||
}
|
||||
|
||||
@@ -851,7 +983,7 @@ void p2m_change_type_global(struct domain *d, p2m_type_t ot, p2m_type_t nt)
|
||||
l1_pgentry_t l1e_content;
|
||||
l1_pgentry_t *l1e;
|
||||
l2_pgentry_t *l2e;
|
||||
mfn_t l1mfn;
|
||||
mfn_t l1mfn, l2mfn;
|
||||
int i1, i2;
|
||||
l3_pgentry_t *l3e;
|
||||
int i3;
|
||||
@@ -891,6 +1023,7 @@ void p2m_change_type_global(struct domain *d, p2m_type_t ot, p2m_type_t nt)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
l2mfn = _mfn(l3e_get_pfn(l3e[i3]));
|
||||
l2e = map_domain_page(l3e_get_pfn(l3e[i3]));
|
||||
for ( i2 = 0; i2 < L2_PAGETABLE_ENTRIES; i2++ )
|
||||
{
|
||||
@@ -899,6 +1032,20 @@ void p2m_change_type_global(struct domain *d, p2m_type_t ot, p2m_type_t nt)
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( (l2e_get_flags(l2e[i2]) & _PAGE_PSE) )
|
||||
{
|
||||
flags = l2e_get_flags(l2e[i2]);
|
||||
if ( p2m_flags_to_type(flags) != ot )
|
||||
continue;
|
||||
mfn = l2e_get_pfn(l2e[i2]);
|
||||
gfn = get_gpfn_from_mfn(mfn);
|
||||
flags = p2m_flags_to_type(nt);
|
||||
l1e_content = l1e_from_pfn(mfn, flags | _PAGE_PSE);
|
||||
paging_write_p2m_entry(d, gfn, (l1_pgentry_t *)&l2e[i2],
|
||||
l2mfn, l1e_content, 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
l1mfn = _mfn(l2e_get_pfn(l2e[i2]));
|
||||
l1e = map_domain_page(mfn_x(l1mfn));
|
||||
|
||||
@@ -944,7 +1091,7 @@ p2m_type_t p2m_change_type(struct domain *d, unsigned long gfn,
|
||||
|
||||
mfn = gfn_to_mfn(d, gfn, &pt);
|
||||
if ( pt == ot )
|
||||
set_p2m_entry(d, gfn, mfn, nt);
|
||||
set_p2m_entry(d, gfn, mfn, 0, nt);
|
||||
|
||||
p2m_unlock(d->arch.p2m);
|
||||
|
||||
@@ -968,7 +1115,7 @@ set_mmio_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn)
|
||||
set_gpfn_from_mfn(mfn_x(omfn), INVALID_M2P_ENTRY);
|
||||
}
|
||||
|
||||
rc = set_p2m_entry(d, gfn, mfn, p2m_mmio_direct);
|
||||
rc = set_p2m_entry(d, gfn, mfn, 0, p2m_mmio_direct);
|
||||
if ( 0 == rc )
|
||||
gdprintk(XENLOG_ERR,
|
||||
"set_mmio_p2m_entry: set_p2m_entry failed! mfn=%08lx\n",
|
||||
@@ -992,7 +1139,7 @@ clear_mmio_p2m_entry(struct domain *d, unsigned long gfn)
|
||||
"clear_mmio_p2m_entry: gfn_to_mfn failed! gfn=%08lx\n", gfn);
|
||||
return 0;
|
||||
}
|
||||
rc = set_p2m_entry(d, gfn, _mfn(INVALID_MFN), 0);
|
||||
rc = set_p2m_entry(d, gfn, _mfn(INVALID_MFN), 0, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -403,7 +403,10 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op)
|
||||
|
||||
if ( xenpxpt->flags == ( XEN_PX_PCT | XEN_PX_PSS |
|
||||
XEN_PX_PSD | XEN_PX_PPC ) )
|
||||
{
|
||||
pxpt->init =1;
|
||||
cpu_count++;
|
||||
}
|
||||
if ( cpu_count == num_online_cpus() )
|
||||
ret = acpi_cpufreq_init();
|
||||
break;
|
||||
|
||||
@@ -1159,7 +1159,7 @@ gnttab_transfer(
|
||||
spin_lock(&e->grant_table->lock);
|
||||
|
||||
sha = &shared_entry(e->grant_table, gop.ref);
|
||||
guest_physmap_add_page(e, sha->frame, mfn);
|
||||
guest_physmap_add_page(e, sha->frame, mfn, 0);
|
||||
sha->frame = mfn;
|
||||
wmb();
|
||||
sha->flags |= GTF_transfer_completed;
|
||||
|
||||
+4
-8
@@ -127,9 +127,7 @@ static void populate_physmap(struct memop_args *a)
|
||||
|
||||
if ( unlikely(paging_mode_translate(d)) )
|
||||
{
|
||||
for ( j = 0; j < (1 << a->extent_order); j++ )
|
||||
if ( guest_physmap_add_page(d, gpfn + j, mfn + j) )
|
||||
goto out;
|
||||
guest_physmap_add_page(d, gpfn, mfn, a->extent_order);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -172,7 +170,7 @@ int guest_remove_page(struct domain *d, unsigned long gmfn)
|
||||
if ( test_and_clear_bit(_PGC_allocated, &page->count_info) )
|
||||
put_page(page);
|
||||
|
||||
guest_physmap_remove_page(d, gmfn, mfn);
|
||||
guest_physmap_remove_page(d, gmfn, mfn, 0);
|
||||
|
||||
put_page(page);
|
||||
|
||||
@@ -419,7 +417,7 @@ static long memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg)
|
||||
if ( !test_and_clear_bit(_PGC_allocated, &page->count_info) )
|
||||
BUG();
|
||||
mfn = page_to_mfn(page);
|
||||
guest_physmap_remove_page(d, mfn_to_gmfn(d, mfn), mfn);
|
||||
guest_physmap_remove_page(d, mfn_to_gmfn(d, mfn), mfn, 0);
|
||||
put_page(page);
|
||||
}
|
||||
|
||||
@@ -440,9 +438,7 @@ static long memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg)
|
||||
mfn = page_to_mfn(page);
|
||||
if ( unlikely(paging_mode_translate(d)) )
|
||||
{
|
||||
/* Ignore failure here. There's nothing we can do. */
|
||||
for ( k = 0; k < (1UL << exch.out.extent_order); k++ )
|
||||
(void)guest_physmap_add_page(d, gpfn + k, mfn + k);
|
||||
guest_physmap_add_page(d, gpfn, mfn, exch.out.extent_order);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include <xen/nodemask.h>
|
||||
#include <xsm/xsm.h>
|
||||
|
||||
extern int do_get_pm_info(struct xen_sysctl_get_pmstat *op);
|
||||
|
||||
extern long arch_do_sysctl(
|
||||
struct xen_sysctl *op, XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl);
|
||||
|
||||
@@ -196,6 +198,20 @@ long do_sysctl(XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl)
|
||||
}
|
||||
break;
|
||||
|
||||
case XEN_SYSCTL_get_pmstat:
|
||||
{
|
||||
ret = do_get_pm_info(&op->u.get_pmstat);
|
||||
if ( ret )
|
||||
break;
|
||||
|
||||
if ( copy_to_guest(u_sysctl, op, 1) )
|
||||
{
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = arch_do_sysctl(op, u_sysctl);
|
||||
break;
|
||||
|
||||
@@ -2,9 +2,13 @@
|
||||
#define __XEN_PROCESSOR_PM_H__
|
||||
|
||||
#include <public/platform.h>
|
||||
#include <public/sysctl.h>
|
||||
|
||||
int get_cpu_id(u8);
|
||||
int acpi_cpufreq_init(void);
|
||||
void px_statistic_update(cpumask_t, uint8_t, uint8_t);
|
||||
int px_statistic_init(int);
|
||||
void px_statistic_reset(int);
|
||||
|
||||
struct processor_performance {
|
||||
uint32_t state;
|
||||
@@ -16,15 +20,32 @@ struct processor_performance {
|
||||
struct xen_psd_package domain_info;
|
||||
cpumask_t shared_cpu_map;
|
||||
uint32_t shared_type;
|
||||
|
||||
uint32_t init;
|
||||
};
|
||||
|
||||
struct processor_pminfo {
|
||||
uint32_t acpi_id;
|
||||
uint32_t id;
|
||||
uint32_t flag;
|
||||
struct processor_performance perf;
|
||||
};
|
||||
|
||||
extern struct processor_pminfo processor_pminfo[NR_CPUS];
|
||||
|
||||
struct px_stat {
|
||||
uint8_t total; /* total Px states */
|
||||
uint8_t usable; /* usable Px states */
|
||||
uint8_t last; /* last Px state */
|
||||
uint8_t cur; /* current Px state */
|
||||
uint64_t *trans_pt; /* Px transition table */
|
||||
pm_px_val_t *pt;
|
||||
};
|
||||
|
||||
struct pm_px {
|
||||
struct px_stat u;
|
||||
uint64_t prev_state_wall;
|
||||
};
|
||||
|
||||
extern struct pm_px px_statistic_data[NR_CPUS];
|
||||
|
||||
#endif /* __XEN_PROCESSOR_PM_H__ */
|
||||
@@ -13,7 +13,7 @@ int create_grant_host_mapping(unsigned long gpaddr, unsigned long mfn,
|
||||
int replace_grant_host_mapping(unsigned long gpaddr, unsigned long mfn, unsigned long new_gpaddr, unsigned int flags);
|
||||
|
||||
// for grant transfer
|
||||
int guest_physmap_add_page(struct domain *d, unsigned long gpfn, unsigned long mfn);
|
||||
int guest_physmap_add_page(struct domain *d, unsigned long gpfn, unsigned long mfn, unsigned int page_order);
|
||||
|
||||
/* XXX
|
||||
* somewhere appropriate
|
||||
|
||||
@@ -40,8 +40,10 @@
|
||||
* Utilities to change relationship of gpfn->mfn for designated domain,
|
||||
* which is required by gnttab transfer, balloon, device model and etc.
|
||||
*/
|
||||
int guest_physmap_add_page(struct domain *d, unsigned long gpfn, unsigned long mfn);
|
||||
void guest_physmap_remove_page(struct domain *d, unsigned long gpfn, unsigned long mfn);
|
||||
int guest_physmap_add_page(struct domain *d, unsigned long gpfn,
|
||||
unsigned long mfn, unsigned int page_order);
|
||||
void guest_physmap_remove_page(struct domain *d, unsigned long gpfn,
|
||||
unsigned long mfn, unsigned int page_order);
|
||||
|
||||
static inline int
|
||||
shadow_mode_enabled(struct domain *d)
|
||||
|
||||
@@ -102,7 +102,8 @@ struct p2m_domain {
|
||||
void (*free_page )(struct domain *d,
|
||||
struct page_info *pg);
|
||||
int (*set_entry )(struct domain *d, unsigned long gfn,
|
||||
mfn_t mfn, p2m_type_t p2mt);
|
||||
mfn_t mfn, unsigned int page_order,
|
||||
p2m_type_t p2mt);
|
||||
mfn_t (*get_entry )(struct domain *d, unsigned long gfn,
|
||||
p2m_type_t *p2mt);
|
||||
mfn_t (*get_entry_current)(unsigned long gfn,
|
||||
@@ -203,21 +204,23 @@ void p2m_final_teardown(struct domain *d);
|
||||
|
||||
/* Add a page to a domain's p2m table */
|
||||
int guest_physmap_add_entry(struct domain *d, unsigned long gfn,
|
||||
unsigned long mfn, p2m_type_t t);
|
||||
unsigned long mfn, unsigned int page_order,
|
||||
p2m_type_t t);
|
||||
|
||||
/* Untyped version for RAM only, for compatibility
|
||||
*
|
||||
* Return 0 for success
|
||||
*/
|
||||
static inline int guest_physmap_add_page(struct domain *d, unsigned long gfn,
|
||||
unsigned long mfn)
|
||||
unsigned long mfn,
|
||||
unsigned int page_order)
|
||||
{
|
||||
return guest_physmap_add_entry(d, gfn, mfn, p2m_ram_rw);
|
||||
return guest_physmap_add_entry(d, gfn, mfn, page_order, p2m_ram_rw);
|
||||
}
|
||||
|
||||
/* Remove a page from a domain's p2m table */
|
||||
void guest_physmap_remove_page(struct domain *d, unsigned long gfn,
|
||||
unsigned long mfn);
|
||||
unsigned long mfn, unsigned int page_order);
|
||||
|
||||
/* Change types across all p2m entries in a domain */
|
||||
void p2m_change_type_global(struct domain *d, p2m_type_t ot, p2m_type_t nt);
|
||||
|
||||
@@ -212,7 +212,41 @@ struct xen_sysctl_availheap {
|
||||
};
|
||||
typedef struct xen_sysctl_availheap xen_sysctl_availheap_t;
|
||||
DEFINE_XEN_GUEST_HANDLE(xen_sysctl_availheap_t);
|
||||
|
||||
|
||||
#define XEN_SYSCTL_get_pmstat 10
|
||||
struct pm_px_val {
|
||||
uint64_aligned_t freq; /* Px core frequency */
|
||||
uint64_aligned_t residency; /* Px residency time */
|
||||
uint64_aligned_t count; /* Px transition count */
|
||||
};
|
||||
typedef struct pm_px_val pm_px_val_t;
|
||||
DEFINE_XEN_GUEST_HANDLE(pm_px_val_t);
|
||||
|
||||
struct pm_px_stat {
|
||||
uint8_t total; /* total Px states */
|
||||
uint8_t usable; /* usable Px states */
|
||||
uint8_t last; /* last Px state */
|
||||
uint8_t cur; /* current Px state */
|
||||
XEN_GUEST_HANDLE_64(uint64) trans_pt; /* Px transition table */
|
||||
XEN_GUEST_HANDLE_64(pm_px_val_t) pt;
|
||||
};
|
||||
typedef struct pm_px_stat pm_px_stat_t;
|
||||
DEFINE_XEN_GUEST_HANDLE(pm_px_stat_t);
|
||||
|
||||
struct xen_sysctl_get_pmstat {
|
||||
#define PMSTAT_get_max_px 0x11
|
||||
#define PMSTAT_get_pxstat 0x12
|
||||
#define PMSTAT_reset_pxstat 0x13
|
||||
uint32_t type;
|
||||
uint32_t cpuid;
|
||||
union {
|
||||
struct pm_px_stat getpx;
|
||||
/* other struct for cx, tx, etc */
|
||||
} u;
|
||||
};
|
||||
typedef struct xen_sysctl_get_pmstat xen_sysctl_get_pmstat_t;
|
||||
DEFINE_XEN_GUEST_HANDLE(xen_sysctl_get_pmstat_t);
|
||||
|
||||
struct xen_sysctl {
|
||||
uint32_t cmd;
|
||||
uint32_t interface_version; /* XEN_SYSCTL_INTERFACE_VERSION */
|
||||
@@ -226,6 +260,7 @@ struct xen_sysctl {
|
||||
struct xen_sysctl_debug_keys debug_keys;
|
||||
struct xen_sysctl_getcpuinfo getcpuinfo;
|
||||
struct xen_sysctl_availheap availheap;
|
||||
struct xen_sysctl_get_pmstat get_pmstat;
|
||||
uint8_t pad[128];
|
||||
} u;
|
||||
};
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#else
|
||||
|
||||
#define paging_mode_translate(d) (0)
|
||||
#define guest_physmap_add_page(d, p, m) (0)
|
||||
#define guest_physmap_remove_page(d, p, m) ((void)0)
|
||||
#define guest_physmap_add_page(d, p, m, o) (0)
|
||||
#define guest_physmap_remove_page(d, p, m, o) ((void)0)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||