mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
Change the location of the shared_info page for auto_translated_physmap guests.
Instead of putting the page outside of the guests pseudo-physical address space, we put it next to the other pages filled by the domain builder, such that the page is already mapped in the initial pagetables and/or a lowmem-type memory mapping. Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
This commit is contained in:
1 parent
fd5de61bb8
commit
e2b8c75165
9 files changed
+201
-106
No files matched your search
@@ -556,10 +556,15 @@ void __init paging_init(void)
|
||||
|
||||
kmap_init();
|
||||
|
||||
/* Switch to the real shared_info page, and clear the dummy page. */
|
||||
set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info);
|
||||
HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
|
||||
memset(empty_zero_page, 0, sizeof(empty_zero_page));
|
||||
if (!xen_feature(XENFEAT_auto_translated_physmap) ||
|
||||
xen_start_info->shared_info >= xen_start_info->nr_pages) {
|
||||
/* Switch to the real shared_info page, and clear the
|
||||
* dummy page. */
|
||||
set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info);
|
||||
HYPERVISOR_shared_info =
|
||||
(shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
|
||||
memset(empty_zero_page, 0, sizeof(empty_zero_page));
|
||||
}
|
||||
|
||||
/* Setup mapping of lower 1st MB */
|
||||
for (i = 0; i < NR_FIX_ISAMAPS; i++)
|
||||
|
||||
@@ -664,6 +664,13 @@ void __init setup_arch(char **cmdline_p)
|
||||
|
||||
setup_xen_features();
|
||||
|
||||
if (xen_feature(XENFEAT_auto_translated_physmap) &&
|
||||
xen_start_info->shared_info < xen_start_info->nr_pages) {
|
||||
HYPERVISOR_shared_info =
|
||||
(shared_info_t *)__va(xen_start_info->shared_info);
|
||||
memset(empty_zero_page, 0, sizeof(empty_zero_page));
|
||||
}
|
||||
|
||||
HYPERVISOR_vm_assist(VMASST_CMD_enable,
|
||||
VMASST_TYPE_writable_pagetables);
|
||||
|
||||
|
||||
@@ -757,10 +757,16 @@ void __init paging_init(void)
|
||||
free_area_init_node(0, NODE_DATA(0), zones,
|
||||
__pa(PAGE_OFFSET) >> PAGE_SHIFT, holes);
|
||||
|
||||
set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info);
|
||||
HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
|
||||
if (!xen_feature(XENFEAT_auto_translated_physmap) ||
|
||||
xen_start_info->shared_info >= xen_start_info->nr_pages) {
|
||||
/* Switch to the real shared_info page, and clear the
|
||||
* dummy page. */
|
||||
set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info);
|
||||
HYPERVISOR_shared_info =
|
||||
(shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
|
||||
memset(empty_zero_page, 0, sizeof(empty_zero_page));
|
||||
}
|
||||
|
||||
memset(empty_zero_page, 0, sizeof(empty_zero_page));
|
||||
init_mm.context.pinned = 1;
|
||||
|
||||
/* Setup mapping of lower 1st MB */
|
||||
|
||||
@@ -37,6 +37,13 @@ static void __init machine_specific_arch_setup(void)
|
||||
struct xen_platform_parameters pp;
|
||||
struct xennmi_callback cb;
|
||||
|
||||
if (xen_feature(XENFEAT_auto_translated_physmap) &&
|
||||
xen_start_info->shared_info < xen_start_info->nr_pages) {
|
||||
HYPERVISOR_shared_info =
|
||||
(shared_info_t *)__va(xen_start_info->shared_info);
|
||||
memset(empty_zero_page, 0, sizeof(empty_zero_page));
|
||||
}
|
||||
|
||||
HYPERVISOR_set_callbacks(
|
||||
__KERNEL_CS, (unsigned long)hypervisor_callback,
|
||||
__KERNEL_CS, (unsigned long)failsafe_callback);
|
||||
|
||||
@@ -606,15 +606,11 @@ static int setup_guest(int xc_handle,
|
||||
struct load_funcs load_funcs;
|
||||
struct domain_setup_info dsi;
|
||||
unsigned long vinitrd_start;
|
||||
unsigned long vinitrd_end;
|
||||
unsigned long vphysmap_start;
|
||||
unsigned long vphysmap_end;
|
||||
unsigned long vstartinfo_start;
|
||||
unsigned long vstartinfo_end;
|
||||
unsigned long vstoreinfo_start;
|
||||
unsigned long vstoreinfo_end;
|
||||
unsigned long vconsole_start;
|
||||
unsigned long vconsole_end;
|
||||
unsigned long vsharedinfo_start = 0; /* XXX gcc */
|
||||
unsigned long vstack_start;
|
||||
unsigned long vstack_end;
|
||||
unsigned long vpt_start;
|
||||
@@ -640,6 +636,34 @@ static int setup_guest(int xc_handle,
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
/* Parse and validate kernel features. */
|
||||
p = strstr(dsi.xen_guest_string, "FEATURES=");
|
||||
if ( p != NULL )
|
||||
{
|
||||
if ( !parse_features(p + strlen("FEATURES="),
|
||||
supported_features,
|
||||
required_features) )
|
||||
{
|
||||
ERROR("Failed to parse guest kernel features.\n");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
printf("Supported features = { %08x }.\n", supported_features[0]);
|
||||
printf("Required features = { %08x }.\n", required_features[0]);
|
||||
}
|
||||
|
||||
for ( i = 0; i < XENFEAT_NR_SUBMAPS; i++ )
|
||||
{
|
||||
if ( (supported_features[i]&required_features[i]) != required_features[i] )
|
||||
{
|
||||
ERROR("Guest kernel does not support a required feature.\n");
|
||||
goto error_out;
|
||||
}
|
||||
}
|
||||
|
||||
shadow_mode_enabled = test_feature_bit(XENFEAT_auto_translated_physmap,
|
||||
required_features);
|
||||
|
||||
/*
|
||||
* Why do we need this? The number of page-table frames depends on the
|
||||
* size of the bootstrap address space. But the size of the address space
|
||||
@@ -647,17 +671,22 @@ static int setup_guest(int xc_handle,
|
||||
* read-only). We have a pair of simultaneous equations in two unknowns,
|
||||
* which we solve by exhaustive search.
|
||||
*/
|
||||
vinitrd_start = round_pgup(dsi.v_end);
|
||||
vinitrd_end = vinitrd_start + initrd->len;
|
||||
vphysmap_start = round_pgup(vinitrd_end);
|
||||
vphysmap_end = vphysmap_start + (nr_pages * sizeof(unsigned long));
|
||||
vstartinfo_start = round_pgup(vphysmap_end);
|
||||
vstartinfo_end = vstartinfo_start + PAGE_SIZE;
|
||||
vstoreinfo_start = vstartinfo_end;
|
||||
vstoreinfo_end = vstoreinfo_start + PAGE_SIZE;
|
||||
vconsole_start = vstoreinfo_end;
|
||||
vconsole_end = vconsole_start + PAGE_SIZE;
|
||||
vpt_start = vconsole_end;
|
||||
v_end = round_pgup(dsi.v_end);
|
||||
vinitrd_start = v_end;
|
||||
v_end += round_pgup(initrd->len);
|
||||
vphysmap_start = v_end;
|
||||
v_end += round_pgup(nr_pages * sizeof(unsigned long));
|
||||
vstartinfo_start = v_end;
|
||||
v_end += PAGE_SIZE;
|
||||
vstoreinfo_start = v_end;
|
||||
v_end += PAGE_SIZE;
|
||||
vconsole_start = v_end;
|
||||
v_end += PAGE_SIZE;
|
||||
if ( shadow_mode_enabled ) {
|
||||
vsharedinfo_start = v_end;
|
||||
v_end += PAGE_SIZE;
|
||||
}
|
||||
vpt_start = v_end;
|
||||
|
||||
for ( nr_pt_pages = 2; ; nr_pt_pages++ )
|
||||
{
|
||||
@@ -697,26 +726,22 @@ static int setup_guest(int xc_handle,
|
||||
|
||||
#define _p(a) ((void *) (a))
|
||||
|
||||
printf("VIRTUAL MEMORY ARRANGEMENT:\n"
|
||||
" Loaded kernel: %p->%p\n"
|
||||
" Init. ramdisk: %p->%p\n"
|
||||
" Phys-Mach map: %p->%p\n"
|
||||
" Start info: %p->%p\n"
|
||||
" Store page: %p->%p\n"
|
||||
" Console page: %p->%p\n"
|
||||
" Page tables: %p->%p\n"
|
||||
" Boot stack: %p->%p\n"
|
||||
" TOTAL: %p->%p\n",
|
||||
_p(dsi.v_kernstart), _p(dsi.v_kernend),
|
||||
_p(vinitrd_start), _p(vinitrd_end),
|
||||
_p(vphysmap_start), _p(vphysmap_end),
|
||||
_p(vstartinfo_start), _p(vstartinfo_end),
|
||||
_p(vstoreinfo_start), _p(vstoreinfo_end),
|
||||
_p(vconsole_start), _p(vconsole_end),
|
||||
_p(vpt_start), _p(vpt_end),
|
||||
_p(vstack_start), _p(vstack_end),
|
||||
_p(dsi.v_start), _p(v_end));
|
||||
printf(" ENTRY ADDRESS: %p\n", _p(dsi.v_kernentry));
|
||||
printf("VIRTUAL MEMORY ARRANGEMENT:\n");
|
||||
printf(" Loaded kernel: %p->%p\n", _p(dsi.v_kernstart),
|
||||
_p(dsi.v_kernend));
|
||||
if ( initrd->len )
|
||||
printf(" Initial ramdisk: %p->%p\n", _p(vinitrd_start),
|
||||
_p(vinitrd_start + initrd->len));
|
||||
printf(" Phys-Mach map: %p\n", _p(vphysmap_start));
|
||||
printf(" Start info: %p\n", _p(vstartinfo_start));
|
||||
printf(" Store page: %p\n", _p(vstoreinfo_start));
|
||||
printf(" Console page: %p\n", _p(vconsole_start));
|
||||
if ( shadow_mode_enabled )
|
||||
printf(" Shared Info page: %p\n", _p(vsharedinfo_start));
|
||||
printf(" Page tables: %p\n", _p(vpt_start));
|
||||
printf(" Boot stack: %p\n", _p(vstack_start));
|
||||
printf(" TOTAL: %p->%p\n", _p(dsi.v_start), _p(v_end));
|
||||
printf(" ENTRY ADDRESS: %p\n", _p(dsi.v_kernentry));
|
||||
|
||||
if ( ((v_end - dsi.v_start)>>PAGE_SHIFT) > nr_pages )
|
||||
{
|
||||
@@ -742,36 +767,6 @@ static int setup_guest(int xc_handle,
|
||||
xc_handle, dom, page_array,
|
||||
&dsi);
|
||||
|
||||
/* Parse and validate kernel features. */
|
||||
p = strstr(dsi.xen_guest_string, "FEATURES=");
|
||||
if ( p != NULL )
|
||||
{
|
||||
if ( !parse_features(p + strlen("FEATURES="),
|
||||
supported_features,
|
||||
required_features) )
|
||||
{
|
||||
ERROR("Failed to parse guest kernel features.\n");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Supported features = { %08x }.\n",
|
||||
supported_features[0]);
|
||||
fprintf(stderr, "Required features = { %08x }.\n",
|
||||
required_features[0]);
|
||||
}
|
||||
|
||||
for ( i = 0; i < XENFEAT_NR_SUBMAPS; i++ )
|
||||
{
|
||||
if ( (supported_features[i]&required_features[i]) != required_features[i] )
|
||||
{
|
||||
ERROR("Guest kernel does not support a required feature.\n");
|
||||
goto error_out;
|
||||
}
|
||||
}
|
||||
|
||||
shadow_mode_enabled = test_feature_bit(
|
||||
XENFEAT_auto_translated_physmap, required_features);
|
||||
|
||||
if ( load_initrd(xc_handle, dom, initrd,
|
||||
vinitrd_start - dsi.v_start, page_array) )
|
||||
goto error_out;
|
||||
@@ -869,6 +864,7 @@ static int setup_guest(int xc_handle,
|
||||
if ( shadow_mode_enabled )
|
||||
{
|
||||
struct xen_reserved_phys_area xrpa;
|
||||
struct xen_map_shared_info xmsi;
|
||||
|
||||
/* Enable shadow translate mode */
|
||||
if ( xc_shadow_control(xc_handle, dom,
|
||||
@@ -889,7 +885,16 @@ static int setup_guest(int xc_handle,
|
||||
PERROR("Cannot find shared info pfn");
|
||||
goto error_out;
|
||||
}
|
||||
guest_shared_info_mfn = xrpa.first_gpfn;
|
||||
|
||||
guest_shared_info_mfn = (vsharedinfo_start-dsi.v_start) >> PAGE_SHIFT;
|
||||
xmsi.domid = dom;
|
||||
xmsi.pfn = guest_shared_info_mfn;
|
||||
rc = xc_memory_op(xc_handle, XENMEM_map_shared_info, &xmsi);
|
||||
if ( rc != 0 )
|
||||
{
|
||||
PERROR("Cannot map shared info pfn");
|
||||
goto error_out;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+41
-6
@@ -2817,14 +2817,15 @@ long do_update_descriptor(u64 pa, u64 desc)
|
||||
|
||||
long arch_memory_op(int op, GUEST_HANDLE(void) arg)
|
||||
{
|
||||
struct xen_reserved_phys_area xrpa;
|
||||
unsigned long pfn;
|
||||
struct domain *d;
|
||||
unsigned int i;
|
||||
|
||||
switch ( op )
|
||||
{
|
||||
case XENMEM_reserved_phys_area:
|
||||
case XENMEM_reserved_phys_area: {
|
||||
struct xen_reserved_phys_area xrpa;
|
||||
|
||||
if ( copy_from_guest(&xrpa, arg, 1) )
|
||||
return -EFAULT;
|
||||
|
||||
@@ -2846,16 +2847,14 @@ long arch_memory_op(int op, GUEST_HANDLE(void) arg)
|
||||
if ( d->arch.first_reserved_pfn == 0 )
|
||||
{
|
||||
d->arch.first_reserved_pfn = pfn = d->max_pages;
|
||||
guest_physmap_add_page(
|
||||
d, pfn + 0, virt_to_maddr(d->shared_info) >> PAGE_SHIFT);
|
||||
for ( i = 0; i < NR_GRANT_FRAMES; i++ )
|
||||
guest_physmap_add_page(
|
||||
d, pfn + 1 + i, gnttab_shared_mfn(d, d->grant_table, i));
|
||||
d, pfn + i, gnttab_shared_mfn(d, d->grant_table, i));
|
||||
}
|
||||
UNLOCK_BIGLOCK(d);
|
||||
|
||||
xrpa.first_gpfn = d->arch.first_reserved_pfn;
|
||||
xrpa.nr_gpfns = 32;
|
||||
xrpa.nr_gpfns = NR_GRANT_FRAMES;
|
||||
|
||||
put_domain(d);
|
||||
|
||||
@@ -2863,6 +2862,42 @@ long arch_memory_op(int op, GUEST_HANDLE(void) arg)
|
||||
return -EFAULT;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case XENMEM_map_shared_info: {
|
||||
struct xen_map_shared_info xmsi;
|
||||
|
||||
if ( copy_from_guest(&xmsi, arg, 1) )
|
||||
return -EFAULT;
|
||||
|
||||
if ( (d = find_domain_by_id(xmsi.domid)) == NULL )
|
||||
return -ESRCH;
|
||||
|
||||
/* Only initialised translated guests can set the shared_info
|
||||
* mapping. */
|
||||
if ( !shadow_mode_translate(d) || (d->max_pages == 0) )
|
||||
{
|
||||
put_domain(d);
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
if ( xmsi.pfn > d->max_pages ) {
|
||||
put_domain(d);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
LOCK_BIGLOCK(d);
|
||||
/* Remove previously mapped page if it was present. */
|
||||
if ( mfn_valid(gmfn_to_mfn(d, xmsi.pfn)) )
|
||||
guest_remove_page(d, xmsi.pfn);
|
||||
guest_physmap_add_page(d, xmsi.pfn,
|
||||
virt_to_maddr(d->shared_info) >> PAGE_SHIFT);
|
||||
UNLOCK_BIGLOCK(d);
|
||||
|
||||
put_domain(d);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return subarch_memory_op(op, arg);
|
||||
|
||||
+39
-26
@@ -137,7 +137,43 @@ populate_physmap(
|
||||
out:
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
guest_remove_page(
|
||||
struct domain *d,
|
||||
unsigned long gmfn)
|
||||
{
|
||||
struct page_info *page;
|
||||
unsigned long mfn;
|
||||
|
||||
mfn = gmfn_to_mfn(d, gmfn);
|
||||
if ( unlikely(!mfn_valid(mfn)) )
|
||||
{
|
||||
DPRINTK("Domain %u page number %lx invalid\n",
|
||||
d->domain_id, mfn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
page = mfn_to_page(mfn);
|
||||
if ( unlikely(!get_page(page, d)) )
|
||||
{
|
||||
DPRINTK("Bad page free for domain %u\n", d->domain_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( test_and_clear_bit(_PGT_pinned, &page->u.inuse.type_info) )
|
||||
put_page_and_type(page);
|
||||
|
||||
if ( test_and_clear_bit(_PGC_allocated, &page->count_info) )
|
||||
put_page(page);
|
||||
|
||||
guest_physmap_remove_page(d, gmfn, mfn);
|
||||
|
||||
put_page(page);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static long
|
||||
decrease_reservation(
|
||||
struct domain *d,
|
||||
@@ -147,8 +183,7 @@ decrease_reservation(
|
||||
unsigned int flags,
|
||||
int *preempted)
|
||||
{
|
||||
struct page_info *page;
|
||||
unsigned long i, j, gmfn, mfn;
|
||||
unsigned long i, j, gmfn;
|
||||
|
||||
if ( !guest_handle_okay(extent_list, nr_extents) )
|
||||
return 0;
|
||||
@@ -166,30 +201,8 @@ decrease_reservation(
|
||||
|
||||
for ( j = 0; j < (1 << extent_order); j++ )
|
||||
{
|
||||
mfn = gmfn_to_mfn(d, gmfn + j);
|
||||
if ( unlikely(!mfn_valid(mfn)) )
|
||||
{
|
||||
DPRINTK("Domain %u page number %lx invalid\n",
|
||||
d->domain_id, mfn);
|
||||
if ( !guest_remove_page(d, gmfn + j) )
|
||||
return i;
|
||||
}
|
||||
|
||||
page = mfn_to_page(mfn);
|
||||
if ( unlikely(!get_page(page, d)) )
|
||||
{
|
||||
DPRINTK("Bad page free for domain %u\n", d->domain_id);
|
||||
return i;
|
||||
}
|
||||
|
||||
if ( test_and_clear_bit(_PGT_pinned, &page->u.inuse.type_info) )
|
||||
put_page_and_type(page);
|
||||
|
||||
if ( test_and_clear_bit(_PGC_allocated, &page->count_info) )
|
||||
put_page(page);
|
||||
|
||||
guest_physmap_remove_page(d, gmfn + j, mfn);
|
||||
|
||||
put_page(page);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -140,6 +140,21 @@ typedef struct xen_translate_gpfn_list {
|
||||
} xen_translate_gpfn_list_t;
|
||||
DEFINE_GUEST_HANDLE(xen_translate_gpfn_list_t);
|
||||
|
||||
/*
|
||||
* Sets the GPFN at which the shared_info_page appears in the specified
|
||||
* guest's pseudophysical address space.
|
||||
* arg == addr of xen_map_shared_info_t.
|
||||
*/
|
||||
#define XENMEM_map_shared_info 9
|
||||
typedef struct xen_map_shared_info {
|
||||
/* Which domain to change the mapping for. */
|
||||
domid_t domid;
|
||||
|
||||
/* GPFN where the shared_info_page should appear. */
|
||||
unsigned long pfn;
|
||||
} xen_map_shared_info_t;
|
||||
DEFINE_GUEST_HANDLE(xen_map_shared_info_t);
|
||||
|
||||
#endif /* __XEN_PUBLIC_MEMORY_H__ */
|
||||
|
||||
/*
|
||||
|
||||
@@ -82,4 +82,6 @@ extern struct list_head page_scrub_list;
|
||||
#define sync_pagetable_state(d) ((void)0)
|
||||
#endif
|
||||
|
||||
int guest_remove_page(struct domain *d, unsigned long gmfn);
|
||||
|
||||
#endif /* __XEN_MM_H__ */
|
||||