mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
New memory hypercall 'populate_physmap'. Accepts a list of
pseudophys frame numbers to be populated with memory. Signed-off-by: Keir Fraser <keir@xensource.com>
This commit is contained in:
1 parent
12f38d5421
commit
6f8668f572
4 files changed
+161
-57
No files matched your search
@@ -315,9 +315,9 @@ int xen_create_contiguous_region(
|
||||
pud_t *pud;
|
||||
pmd_t *pmd;
|
||||
pte_t *pte;
|
||||
unsigned long mfn, i, flags;
|
||||
unsigned long frame, i, flags;
|
||||
struct xen_memory_reservation reservation = {
|
||||
.extent_start = &mfn,
|
||||
.extent_start = &frame,
|
||||
.nr_extents = 1,
|
||||
.extent_order = 0,
|
||||
.domid = DOMID_SELF
|
||||
@@ -333,7 +333,7 @@ int xen_create_contiguous_region(
|
||||
pud = pud_offset(pgd, (vstart + (i*PAGE_SIZE)));
|
||||
pmd = pmd_offset(pud, (vstart + (i*PAGE_SIZE)));
|
||||
pte = pte_offset_kernel(pmd, (vstart + (i*PAGE_SIZE)));
|
||||
mfn = pte_mfn(*pte);
|
||||
frame = pte_mfn(*pte);
|
||||
BUG_ON(HYPERVISOR_update_va_mapping(
|
||||
vstart + (i*PAGE_SIZE), __pte_ma(0), 0));
|
||||
set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i,
|
||||
@@ -345,7 +345,8 @@ int xen_create_contiguous_region(
|
||||
/* 2. Get a new contiguous memory extent. */
|
||||
reservation.extent_order = order;
|
||||
reservation.address_bits = address_bits;
|
||||
if (HYPERVISOR_memory_op(XENMEM_increase_reservation,
|
||||
frame = __pa(vstart) >> PAGE_SHIFT;
|
||||
if (HYPERVISOR_memory_op(XENMEM_populate_physmap,
|
||||
&reservation) != 1)
|
||||
goto fail;
|
||||
|
||||
@@ -353,9 +354,8 @@ int xen_create_contiguous_region(
|
||||
for (i = 0; i < (1<<order); i++) {
|
||||
BUG_ON(HYPERVISOR_update_va_mapping(
|
||||
vstart + (i*PAGE_SIZE),
|
||||
pfn_pte_ma(mfn+i, PAGE_KERNEL), 0));
|
||||
xen_machphys_update(mfn+i, (__pa(vstart)>>PAGE_SHIFT)+i);
|
||||
set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i, mfn+i);
|
||||
pfn_pte_ma(frame+i, PAGE_KERNEL), 0));
|
||||
set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i, frame+i);
|
||||
}
|
||||
|
||||
flush_tlb_all();
|
||||
@@ -371,13 +371,13 @@ int xen_create_contiguous_region(
|
||||
reservation.address_bits = 0;
|
||||
|
||||
for (i = 0; i < (1<<order); i++) {
|
||||
frame = (__pa(vstart) >> PAGE_SHIFT) + i;
|
||||
BUG_ON(HYPERVISOR_memory_op(
|
||||
XENMEM_increase_reservation, &reservation) != 1);
|
||||
XENMEM_populate_physmap, &reservation) != 1);
|
||||
BUG_ON(HYPERVISOR_update_va_mapping(
|
||||
vstart + (i*PAGE_SIZE),
|
||||
pfn_pte_ma(mfn, PAGE_KERNEL), 0));
|
||||
xen_machphys_update(mfn, (__pa(vstart)>>PAGE_SHIFT)+i);
|
||||
set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i, mfn);
|
||||
pfn_pte_ma(frame, PAGE_KERNEL), 0));
|
||||
set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i, frame);
|
||||
}
|
||||
|
||||
flush_tlb_all();
|
||||
@@ -393,9 +393,9 @@ void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
|
||||
pud_t *pud;
|
||||
pmd_t *pmd;
|
||||
pte_t *pte;
|
||||
unsigned long mfn, i, flags;
|
||||
unsigned long frame, i, flags;
|
||||
struct xen_memory_reservation reservation = {
|
||||
.extent_start = &mfn,
|
||||
.extent_start = &frame,
|
||||
.nr_extents = 1,
|
||||
.extent_order = 0,
|
||||
.domid = DOMID_SELF
|
||||
@@ -413,7 +413,7 @@ void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
|
||||
pud = pud_offset(pgd, (vstart + (i*PAGE_SIZE)));
|
||||
pmd = pmd_offset(pud, (vstart + (i*PAGE_SIZE)));
|
||||
pte = pte_offset_kernel(pmd, (vstart + (i*PAGE_SIZE)));
|
||||
mfn = pte_mfn(*pte);
|
||||
frame = pte_mfn(*pte);
|
||||
BUG_ON(HYPERVISOR_update_va_mapping(
|
||||
vstart + (i*PAGE_SIZE), __pte_ma(0), 0));
|
||||
set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i,
|
||||
@@ -424,13 +424,13 @@ void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
|
||||
|
||||
/* 2. Map new pages in place of old pages. */
|
||||
for (i = 0; i < (1<<order); i++) {
|
||||
frame = (__pa(vstart) >> PAGE_SHIFT) + i;
|
||||
BUG_ON(HYPERVISOR_memory_op(
|
||||
XENMEM_increase_reservation, &reservation) != 1);
|
||||
XENMEM_populate_physmap, &reservation) != 1);
|
||||
BUG_ON(HYPERVISOR_update_va_mapping(
|
||||
vstart + (i*PAGE_SIZE),
|
||||
pfn_pte_ma(mfn, PAGE_KERNEL), 0));
|
||||
xen_machphys_update(mfn, (__pa(vstart)>>PAGE_SHIFT)+i);
|
||||
set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i, mfn);
|
||||
pfn_pte_ma(frame, PAGE_KERNEL), 0));
|
||||
set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i, frame);
|
||||
}
|
||||
|
||||
flush_tlb_all();
|
||||
|
||||
@@ -139,6 +139,21 @@ static struct page *balloon_retrieve(void)
|
||||
return page;
|
||||
}
|
||||
|
||||
static struct page *balloon_first_page(void)
|
||||
{
|
||||
if (list_empty(&ballooned_pages))
|
||||
return NULL;
|
||||
return LIST_TO_PAGE(ballooned_pages.next);
|
||||
}
|
||||
|
||||
static struct page *balloon_next_page(struct page *page)
|
||||
{
|
||||
struct list_head *next = PAGE_TO_LIST(page)->next;
|
||||
if (next == &ballooned_pages)
|
||||
return NULL;
|
||||
return LIST_TO_PAGE(next);
|
||||
}
|
||||
|
||||
static void balloon_alarm(unsigned long unused)
|
||||
{
|
||||
schedule_work(&balloon_worker);
|
||||
@@ -154,7 +169,7 @@ static unsigned long current_target(void)
|
||||
|
||||
static int increase_reservation(unsigned long nr_pages)
|
||||
{
|
||||
unsigned long *mfn_list, pfn, i, flags;
|
||||
unsigned long *frame_list, pfn, i, flags;
|
||||
struct page *page;
|
||||
long rc;
|
||||
struct xen_memory_reservation reservation = {
|
||||
@@ -166,20 +181,27 @@ static int increase_reservation(unsigned long nr_pages)
|
||||
if (nr_pages > (PAGE_SIZE / sizeof(unsigned long)))
|
||||
nr_pages = PAGE_SIZE / sizeof(unsigned long);
|
||||
|
||||
mfn_list = (unsigned long *)__get_free_page(GFP_KERNEL);
|
||||
if (mfn_list == NULL)
|
||||
frame_list = (unsigned long *)__get_free_page(GFP_KERNEL);
|
||||
if (frame_list == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
balloon_lock(flags);
|
||||
|
||||
reservation.extent_start = mfn_list;
|
||||
page = balloon_first_page();
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
BUG_ON(page == NULL);
|
||||
frame_list[i] = page_to_pfn(page);;
|
||||
page = balloon_next_page(page);
|
||||
}
|
||||
|
||||
reservation.extent_start = frame_list;
|
||||
reservation.nr_extents = nr_pages;
|
||||
rc = HYPERVISOR_memory_op(
|
||||
XENMEM_increase_reservation, &reservation);
|
||||
XENMEM_populate_physmap, &reservation);
|
||||
if (rc < nr_pages) {
|
||||
int ret;
|
||||
/* We hit the Xen hard limit: reprobe. */
|
||||
reservation.extent_start = mfn_list;
|
||||
reservation.extent_start = frame_list;
|
||||
reservation.nr_extents = rc;
|
||||
ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
|
||||
&reservation);
|
||||
@@ -196,15 +218,15 @@ static int increase_reservation(unsigned long nr_pages)
|
||||
BUG_ON(phys_to_machine_mapping_valid(pfn));
|
||||
|
||||
/* Update P->M and M->P tables. */
|
||||
set_phys_to_machine(pfn, mfn_list[i]);
|
||||
xen_machphys_update(mfn_list[i], pfn);
|
||||
set_phys_to_machine(pfn, frame_list[i]);
|
||||
xen_machphys_update(frame_list[i], pfn);
|
||||
|
||||
/* Link back into the page tables if not highmem. */
|
||||
if (pfn < max_low_pfn) {
|
||||
int ret;
|
||||
ret = HYPERVISOR_update_va_mapping(
|
||||
(unsigned long)__va(pfn << PAGE_SHIFT),
|
||||
pfn_pte_ma(mfn_list[i], PAGE_KERNEL),
|
||||
pfn_pte_ma(frame_list[i], PAGE_KERNEL),
|
||||
0);
|
||||
BUG_ON(ret);
|
||||
}
|
||||
@@ -221,14 +243,14 @@ static int increase_reservation(unsigned long nr_pages)
|
||||
out:
|
||||
balloon_unlock(flags);
|
||||
|
||||
free_page((unsigned long)mfn_list);
|
||||
free_page((unsigned long)frame_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decrease_reservation(unsigned long nr_pages)
|
||||
{
|
||||
unsigned long *mfn_list, pfn, i, flags;
|
||||
unsigned long *frame_list, pfn, i, flags;
|
||||
struct page *page;
|
||||
void *v;
|
||||
int need_sleep = 0;
|
||||
@@ -242,8 +264,8 @@ static int decrease_reservation(unsigned long nr_pages)
|
||||
if (nr_pages > (PAGE_SIZE / sizeof(unsigned long)))
|
||||
nr_pages = PAGE_SIZE / sizeof(unsigned long);
|
||||
|
||||
mfn_list = (unsigned long *)__get_free_page(GFP_KERNEL);
|
||||
if (mfn_list == NULL)
|
||||
frame_list = (unsigned long *)__get_free_page(GFP_KERNEL);
|
||||
if (frame_list == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
@@ -254,7 +276,7 @@ static int decrease_reservation(unsigned long nr_pages)
|
||||
}
|
||||
|
||||
pfn = page_to_pfn(page);
|
||||
mfn_list[i] = pfn_to_mfn(pfn);
|
||||
frame_list[i] = pfn_to_mfn(pfn);
|
||||
|
||||
if (!PageHighMem(page)) {
|
||||
v = phys_to_virt(pfn << PAGE_SHIFT);
|
||||
@@ -280,12 +302,12 @@ static int decrease_reservation(unsigned long nr_pages)
|
||||
|
||||
/* No more mappings: invalidate P2M and add to balloon. */
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
pfn = mfn_to_pfn(mfn_list[i]);
|
||||
pfn = mfn_to_pfn(frame_list[i]);
|
||||
set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
|
||||
balloon_append(pfn_to_page(pfn));
|
||||
}
|
||||
|
||||
reservation.extent_start = mfn_list;
|
||||
reservation.extent_start = frame_list;
|
||||
reservation.nr_extents = nr_pages;
|
||||
ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
|
||||
BUG_ON(ret != nr_pages);
|
||||
@@ -295,7 +317,7 @@ static int decrease_reservation(unsigned long nr_pages)
|
||||
|
||||
balloon_unlock(flags);
|
||||
|
||||
free_page((unsigned long)mfn_list);
|
||||
free_page((unsigned long)frame_list);
|
||||
|
||||
return need_sleep;
|
||||
}
|
||||
|
||||
+91
-15
@@ -30,7 +30,7 @@ increase_reservation(
|
||||
int *preempted)
|
||||
{
|
||||
struct pfn_info *page;
|
||||
unsigned int i;
|
||||
unsigned long i;
|
||||
|
||||
if ( (extent_list != NULL) &&
|
||||
!array_access_ok(extent_list, nr_extents, sizeof(*extent_list)) )
|
||||
@@ -52,7 +52,7 @@ increase_reservation(
|
||||
d, extent_order, flags)) == NULL) )
|
||||
{
|
||||
DPRINTK("Could not allocate order=%d extent: "
|
||||
"id=%d flags=%x (%d of %d)\n",
|
||||
"id=%d flags=%x (%ld of %d)\n",
|
||||
extent_order, d->domain_id, flags, i, nr_extents);
|
||||
return i;
|
||||
}
|
||||
@@ -66,6 +66,58 @@ increase_reservation(
|
||||
return nr_extents;
|
||||
}
|
||||
|
||||
static long
|
||||
populate_physmap(
|
||||
struct domain *d,
|
||||
unsigned long *extent_list,
|
||||
unsigned int nr_extents,
|
||||
unsigned int extent_order,
|
||||
unsigned int flags,
|
||||
int *preempted)
|
||||
{
|
||||
struct pfn_info *page;
|
||||
unsigned long i, j, pfn, mfn;
|
||||
|
||||
if ( !array_access_ok(extent_list, nr_extents, sizeof(*extent_list)) )
|
||||
return 0;
|
||||
|
||||
if ( (extent_order != 0) &&
|
||||
!multipage_allocation_permitted(current->domain) )
|
||||
return 0;
|
||||
|
||||
for ( i = 0; i < nr_extents; i++ )
|
||||
{
|
||||
if ( hypercall_preempt_check() )
|
||||
{
|
||||
*preempted = 1;
|
||||
return i;
|
||||
}
|
||||
|
||||
if ( unlikely((page = alloc_domheap_pages(
|
||||
d, extent_order, flags)) == NULL) )
|
||||
{
|
||||
DPRINTK("Could not allocate order=%d extent: "
|
||||
"id=%d flags=%x (%ld of %d)\n",
|
||||
extent_order, d->domain_id, flags, i, nr_extents);
|
||||
return i;
|
||||
}
|
||||
|
||||
mfn = page_to_pfn(page);
|
||||
|
||||
if ( unlikely(__get_user(pfn, &extent_list[i]) != 0) )
|
||||
return i;
|
||||
|
||||
for ( j = 0; j < (1 << extent_order); j++ )
|
||||
set_pfn_from_mfn(mfn + j, pfn + j);
|
||||
|
||||
/* Inform the domain of the new page's machine address. */
|
||||
if ( __put_user(mfn, &extent_list[i]) != 0 )
|
||||
return i;
|
||||
}
|
||||
|
||||
return nr_extents;
|
||||
}
|
||||
|
||||
static long
|
||||
decrease_reservation(
|
||||
struct domain *d,
|
||||
@@ -76,7 +128,7 @@ decrease_reservation(
|
||||
int *preempted)
|
||||
{
|
||||
struct pfn_info *page;
|
||||
unsigned long i, j, mpfn;
|
||||
unsigned long i, j, mfn;
|
||||
|
||||
if ( !array_access_ok(extent_list, nr_extents, sizeof(*extent_list)) )
|
||||
return 0;
|
||||
@@ -89,19 +141,19 @@ decrease_reservation(
|
||||
return i;
|
||||
}
|
||||
|
||||
if ( unlikely(__get_user(mpfn, &extent_list[i]) != 0) )
|
||||
if ( unlikely(__get_user(mfn, &extent_list[i]) != 0) )
|
||||
return i;
|
||||
|
||||
for ( j = 0; j < (1 << extent_order); j++ )
|
||||
{
|
||||
if ( unlikely((mpfn + j) >= max_page) )
|
||||
if ( unlikely((mfn + j) >= max_page) )
|
||||
{
|
||||
DPRINTK("Domain %u page number out of range (%lx >= %lx)\n",
|
||||
d->domain_id, mpfn + j, max_page);
|
||||
d->domain_id, mfn + j, max_page);
|
||||
return i;
|
||||
}
|
||||
|
||||
page = pfn_to_page(mpfn + j);
|
||||
page = pfn_to_page(mfn + j);
|
||||
if ( unlikely(!get_page(page, d)) )
|
||||
{
|
||||
DPRINTK("Bad page free for domain %u\n", d->domain_id);
|
||||
@@ -143,6 +195,7 @@ long do_memory_op(int cmd, void *arg)
|
||||
{
|
||||
case XENMEM_increase_reservation:
|
||||
case XENMEM_decrease_reservation:
|
||||
case XENMEM_populate_physmap:
|
||||
if ( copy_from_user(&reservation, arg, sizeof(reservation)) )
|
||||
return -EFAULT;
|
||||
|
||||
@@ -170,14 +223,37 @@ long do_memory_op(int cmd, void *arg)
|
||||
else if ( (d = find_domain_by_id(reservation.domid)) == NULL )
|
||||
return -ESRCH;
|
||||
|
||||
rc = ((op == XENMEM_increase_reservation) ?
|
||||
increase_reservation : decrease_reservation)(
|
||||
d,
|
||||
reservation.extent_start,
|
||||
reservation.nr_extents,
|
||||
reservation.extent_order,
|
||||
flags,
|
||||
&preempted);
|
||||
switch ( op )
|
||||
{
|
||||
case XENMEM_increase_reservation:
|
||||
rc = increase_reservation(
|
||||
d,
|
||||
reservation.extent_start,
|
||||
reservation.nr_extents,
|
||||
reservation.extent_order,
|
||||
flags,
|
||||
&preempted);
|
||||
break;
|
||||
case XENMEM_decrease_reservation:
|
||||
rc = decrease_reservation(
|
||||
d,
|
||||
reservation.extent_start,
|
||||
reservation.nr_extents,
|
||||
reservation.extent_order,
|
||||
flags,
|
||||
&preempted);
|
||||
break;
|
||||
case XENMEM_populate_physmap:
|
||||
default:
|
||||
rc = populate_physmap(
|
||||
d,
|
||||
reservation.extent_start,
|
||||
reservation.nr_extents,
|
||||
reservation.extent_order,
|
||||
flags,
|
||||
&preempted);
|
||||
break;
|
||||
}
|
||||
|
||||
if ( unlikely(reservation.domid != DOMID_SELF) )
|
||||
put_domain(d);
|
||||
|
||||
@@ -16,11 +16,18 @@
|
||||
*/
|
||||
#define XENMEM_increase_reservation 0
|
||||
#define XENMEM_decrease_reservation 1
|
||||
#define XENMEM_populate_physmap 6
|
||||
typedef struct xen_memory_reservation {
|
||||
|
||||
/*
|
||||
* MFN bases of extents to free (XENMEM_decrease_reservation).
|
||||
* MFN bases of extents that were allocated (XENMEM_increase_reservation).
|
||||
* XENMEM_increase_reservation:
|
||||
* OUT: MFN bases of extents that were allocated
|
||||
* XENMEM_decrease_reservation:
|
||||
* IN: MFN bases of extents to free
|
||||
* XENMEM_populate_physmap:
|
||||
* IN: PFN bases of extents to populate with memory
|
||||
* OUT: MFN bases of extents that were allocated
|
||||
* (NB. This command also updates the mach_to_phys translation table)
|
||||
*/
|
||||
unsigned long *extent_start;
|
||||
|
||||
@@ -29,11 +36,10 @@ typedef struct xen_memory_reservation {
|
||||
unsigned int extent_order;
|
||||
|
||||
/*
|
||||
* XENMEM_increase_reservation: maximum # bits addressable by the user
|
||||
* of the allocated region (e.g., I/O devices often have a 32-bit
|
||||
* limitation even in 64-bit systems). If zero then the user has no
|
||||
* addressing restriction.
|
||||
* XENMEM_decrease_reservation: unused.
|
||||
* Mmaximum # bits addressable by the user of the allocated region (e.g.,
|
||||
* I/O devices often have a 32-bit limitation even in 64-bit systems). If
|
||||
* zero then the user has no addressing restriction.
|
||||
* This field is not used by XENMEM_decrease_reservation.
|
||||
*/
|
||||
unsigned int address_bits;
|
||||
|
||||
|
||||