Mailing List Archive

Improved handling of non-RAM pages. Deal with RAM holes.
ChangeSet 1.1159.256.93, 2005/04/14 21:49:01+01:00, kaf24@firebug.cl.cam.ac.uk

Improved handling of non-RAM pages. Deal with RAM holes.
Signed-off-by: Keir Fraser <keir@xensource.com>



arch/x86/memory.c | 80 +++++++++++++++++++++++++++++++++----------------
common/grant_table.c | 2 -
include/asm-x86/page.h | 9 -----
3 files changed, 57 insertions(+), 34 deletions(-)


diff -Nru a/xen/arch/x86/memory.c b/xen/arch/x86/memory.c
--- a/xen/arch/x86/memory.c 2005-04-14 17:03:17 -04:00
+++ b/xen/arch/x86/memory.c 2005-04-14 17:03:17 -04:00
@@ -101,6 +101,7 @@
#include <asm/uaccess.h>
#include <asm/domain_page.h>
#include <asm/ldt.h>
+#include <asm/e820.h>

#ifdef VERBOSE
#define MEM_LOG(_f, _a...) \
@@ -168,7 +169,8 @@

void arch_init_memory(void)
{
- unsigned long i;
+ unsigned long i, j, pfn, nr_pfns;
+ struct pfn_info *page;

/*
* We are rather picky about the layout of 'struct pfn_info'. The
@@ -203,8 +205,8 @@

/*
* Initialise our DOMID_IO domain.
- * This domain owns no pages but is considered a special case when
- * mapping I/O pages, as the mappings occur at the priv of the caller.
+ * This domain owns I/O pages that are within the range of the pfn_info
+ * array. Mappings occur at the priv of the caller.
*/
dom_io = alloc_domain_struct();
atomic_set(&dom_io->refcnt, 1);
@@ -213,11 +215,40 @@
/* M2P table is mappable read-only by privileged domains. */
for ( i = 0; i < 1024; i++ )
{
- frame_table[m2p_start_mfn+i].count_info = PGC_allocated | 1;
- /* gdt to make sure it's only mapped read-only by non-privileged
- domains. */
- frame_table[m2p_start_mfn+i].u.inuse.type_info = PGT_gdt_page | 1;
- frame_table[m2p_start_mfn+i].u.inuse.domain = dom_xen;
+ /* Ensure it's mapped read-only by guests (use GDT type). */
+ page = &frame_table[m2p_start_mfn+i];
+ page->count_info = PGC_allocated | 1;
+ page->u.inuse.type_info = PGT_gdt_page | PGT_validated | 1;
+ page->u.inuse.domain = dom_xen;
+ }
+
+ /* First 1MB of RAM is historically marked as I/O. */
+ for ( i = 0; i < 0x100; i++ )
+ {
+ page = &frame_table[i];
+ page->count_info = PGC_allocated | 1;
+ page->u.inuse.type_info = PGT_writable_page | PGT_validated | 1;
+ page->u.inuse.domain = dom_io;
+ }
+
+ /* Any non-RAM areas in the e820 map are considered to be for I/O. */
+ for ( i = 0; i < e820.nr_map; i++ )
+ {
+ if ( e820.map[i].type == E820_RAM )
+ continue;
+ pfn = e820.map[i].addr >> PAGE_SHIFT;
+ nr_pfns = (e820.map[i].size +
+ (e820.map[i].addr & ~PAGE_MASK) +
+ ~PAGE_MASK) >> PAGE_SHIFT;
+ for ( j = 0; j < nr_pfns; j++ )
+ {
+ if ( !pfn_valid(pfn+j) )
+ continue;
+ page = &frame_table[pfn+j];
+ page->count_info = PGC_allocated | 1;
+ page->u.inuse.type_info = PGT_writable_page | PGT_validated | 1;
+ page->u.inuse.domain = dom_io;
+ }
}
}

@@ -298,13 +329,7 @@
{
struct pfn_info *page = &frame_table[page_nr];

- if ( unlikely(!pfn_is_ram(page_nr)) )
- {
- MEM_LOG("Pfn %08lx is not RAM", page_nr);
- return 0;
- }
-
- if ( unlikely(!get_page(page, d)) )
+ if ( unlikely(!pfn_valid(page_nr)) || unlikely(!get_page(page, d)) )
{
MEM_LOG("Could not get page ref for pfn %08lx", page_nr);
return 0;
@@ -410,20 +435,25 @@
return 0;
}

- if ( unlikely(!pfn_is_ram(pfn)) )
+ if ( unlikely(!pfn_valid(pfn)) ||
+ unlikely(page->u.inuse.domain == dom_io) )
{
- /* Revert to caller privileges if FD == DOMID_IO. */
+ /* DOMID_IO reverts to caller for privilege checks. */
if ( d == dom_io )
d = current;

- if ( IS_PRIV(d) )
- return 1;
+ if ( (!IS_PRIV(d)) &&
+ (!IS_CAPABLE_PHYSDEV(d) || !domain_iomem_in_pfn(d, pfn)) )
+ {
+ MEM_LOG("Non-privileged attempt to map I/O space %08lx", pfn);
+ return 0;
+ }

- if ( IS_CAPABLE_PHYSDEV(d) )
- return domain_iomem_in_pfn(d, pfn);
+ /* No reference counting for out-of-range I/O pages. */
+ if ( !pfn_valid(pfn) )
+ return 1;

- MEM_LOG("Non-privileged attempt to map I/O space %08lx", pfn);
- return 0;
+ d = dom_io;
}

return ((l1v & _PAGE_RW) ?
@@ -468,7 +498,7 @@
struct pfn_info *page = &frame_table[pfn];
struct domain *e;

- if ( !(l1v & _PAGE_PRESENT) || !pfn_is_ram(pfn) )
+ if ( !(l1v & _PAGE_PRESENT) || !pfn_valid(pfn) )
return;

e = page->u.inuse.domain;
@@ -1114,7 +1144,7 @@
gntref = (grant_ref_t)((val & 0xFF00) | ((ptr >> 2) & 0x00FF));

if ( unlikely(IS_XEN_HEAP_FRAME(page)) ||
- unlikely(!pfn_is_ram(pfn)) ||
+ unlikely(!pfn_valid(pfn)) ||
unlikely((e = find_domain_by_id(domid)) == NULL) )
{
MEM_LOG("Bad frame (%08lx) or bad domid (%d).\n", pfn, domid);
diff -Nru a/xen/common/grant_table.c b/xen/common/grant_table.c
--- a/xen/common/grant_table.c 2005-04-14 17:03:17 -04:00
+++ b/xen/common/grant_table.c 2005-04-14 17:03:17 -04:00
@@ -169,7 +169,7 @@

/* rmb(); */ /* not on x86 */
frame = sha->frame;
- if ( unlikely(!pfn_is_ram(frame)) ||
+ if ( unlikely(!pfn_valid(frame)) ||
unlikely(!((flags & GNTMAP_readonly) ?
get_page(&frame_table[frame], rd) :
get_page_and_type(&frame_table[frame], rd,
diff -Nru a/xen/include/asm-x86/page.h b/xen/include/asm-x86/page.h
--- a/xen/include/asm-x86/page.h 2005-04-14 17:03:17 -04:00
+++ b/xen/include/asm-x86/page.h 2005-04-14 17:03:17 -04:00
@@ -105,14 +105,7 @@
#define pfn_to_page(_pfn) (frame_table + (_pfn))
#define phys_to_page(kaddr) (frame_table + ((kaddr) >> PAGE_SHIFT))
#define virt_to_page(kaddr) (frame_table + (__pa(kaddr) >> PAGE_SHIFT))
-#define VALID_PAGE(page) ((page - frame_table) < max_mapnr)
-
-/*
- * NB. We don't currently track I/O holes in the physical RAM space.
- * For now we guess that I/O devices will be mapped in the first 1MB
- * (e.g., VGA buffers) or beyond the end of physical RAM.
- */
-#define pfn_is_ram(_pfn) (((_pfn) > 0x100) && ((_pfn) < max_page))
+#define pfn_valid(_pfn) ((_pfn) < max_page)

/* High table entries are reserved by the hypervisor. */
#define DOMAIN_ENTRIES_PER_L2_PAGETABLE \

_______________________________________________
Xen-changelog mailing list
Xen-changelog@lists.xensource.com
http://lists.xensource.com/xen-changelog
Improved handling of non-RAM pages. Deal with RAM holes. [ In reply to ]
ChangeSet 1.1827, 2005/04/14 21:49:01+01:00, kaf24@firebug.cl.cam.ac.uk

Improved handling of non-RAM pages. Deal with RAM holes.
Signed-off-by: Keir Fraser <keir@xensource.com>



arch/x86/memory.c | 80 +++++++++++++++++++++++++++++++++----------------
common/grant_table.c | 2 -
include/asm-x86/page.h | 9 -----
3 files changed, 57 insertions(+), 34 deletions(-)


diff -Nru a/xen/arch/x86/memory.c b/xen/arch/x86/memory.c
--- a/xen/arch/x86/memory.c 2005-04-14 17:04:15 -04:00
+++ b/xen/arch/x86/memory.c 2005-04-14 17:04:15 -04:00
@@ -101,6 +101,7 @@
#include <asm/uaccess.h>
#include <asm/domain_page.h>
#include <asm/ldt.h>
+#include <asm/e820.h>

#ifdef VERBOSE
#define MEM_LOG(_f, _a...) \
@@ -168,7 +169,8 @@

void arch_init_memory(void)
{
- unsigned long i;
+ unsigned long i, j, pfn, nr_pfns;
+ struct pfn_info *page;

/*
* We are rather picky about the layout of 'struct pfn_info'. The
@@ -203,8 +205,8 @@

/*
* Initialise our DOMID_IO domain.
- * This domain owns no pages but is considered a special case when
- * mapping I/O pages, as the mappings occur at the priv of the caller.
+ * This domain owns I/O pages that are within the range of the pfn_info
+ * array. Mappings occur at the priv of the caller.
*/
dom_io = alloc_domain_struct();
atomic_set(&dom_io->refcnt, 1);
@@ -213,11 +215,40 @@
/* M2P table is mappable read-only by privileged domains. */
for ( i = 0; i < 1024; i++ )
{
- frame_table[m2p_start_mfn+i].count_info = PGC_allocated | 1;
- /* gdt to make sure it's only mapped read-only by non-privileged
- domains. */
- frame_table[m2p_start_mfn+i].u.inuse.type_info = PGT_gdt_page | 1;
- frame_table[m2p_start_mfn+i].u.inuse.domain = dom_xen;
+ /* Ensure it's mapped read-only by guests (use GDT type). */
+ page = &frame_table[m2p_start_mfn+i];
+ page->count_info = PGC_allocated | 1;
+ page->u.inuse.type_info = PGT_gdt_page | PGT_validated | 1;
+ page->u.inuse.domain = dom_xen;
+ }
+
+ /* First 1MB of RAM is historically marked as I/O. */
+ for ( i = 0; i < 0x100; i++ )
+ {
+ page = &frame_table[i];
+ page->count_info = PGC_allocated | 1;
+ page->u.inuse.type_info = PGT_writable_page | PGT_validated | 1;
+ page->u.inuse.domain = dom_io;
+ }
+
+ /* Any non-RAM areas in the e820 map are considered to be for I/O. */
+ for ( i = 0; i < e820.nr_map; i++ )
+ {
+ if ( e820.map[i].type == E820_RAM )
+ continue;
+ pfn = e820.map[i].addr >> PAGE_SHIFT;
+ nr_pfns = (e820.map[i].size +
+ (e820.map[i].addr & ~PAGE_MASK) +
+ ~PAGE_MASK) >> PAGE_SHIFT;
+ for ( j = 0; j < nr_pfns; j++ )
+ {
+ if ( !pfn_valid(pfn+j) )
+ continue;
+ page = &frame_table[pfn+j];
+ page->count_info = PGC_allocated | 1;
+ page->u.inuse.type_info = PGT_writable_page | PGT_validated | 1;
+ page->u.inuse.domain = dom_io;
+ }
}
}

@@ -298,13 +329,7 @@
{
struct pfn_info *page = &frame_table[page_nr];

- if ( unlikely(!pfn_is_ram(page_nr)) )
- {
- MEM_LOG("Pfn %08lx is not RAM", page_nr);
- return 0;
- }
-
- if ( unlikely(!get_page(page, d)) )
+ if ( unlikely(!pfn_valid(page_nr)) || unlikely(!get_page(page, d)) )
{
MEM_LOG("Could not get page ref for pfn %08lx", page_nr);
return 0;
@@ -410,20 +435,25 @@
return 0;
}

- if ( unlikely(!pfn_is_ram(pfn)) )
+ if ( unlikely(!pfn_valid(pfn)) ||
+ unlikely(page->u.inuse.domain == dom_io) )
{
- /* Revert to caller privileges if FD == DOMID_IO. */
+ /* DOMID_IO reverts to caller for privilege checks. */
if ( d == dom_io )
d = current;

- if ( IS_PRIV(d) )
- return 1;
+ if ( (!IS_PRIV(d)) &&
+ (!IS_CAPABLE_PHYSDEV(d) || !domain_iomem_in_pfn(d, pfn)) )
+ {
+ MEM_LOG("Non-privileged attempt to map I/O space %08lx", pfn);
+ return 0;
+ }

- if ( IS_CAPABLE_PHYSDEV(d) )
- return domain_iomem_in_pfn(d, pfn);
+ /* No reference counting for out-of-range I/O pages. */
+ if ( !pfn_valid(pfn) )
+ return 1;

- MEM_LOG("Non-privileged attempt to map I/O space %08lx", pfn);
- return 0;
+ d = dom_io;
}

return ((l1v & _PAGE_RW) ?
@@ -468,7 +498,7 @@
struct pfn_info *page = &frame_table[pfn];
struct domain *e;

- if ( !(l1v & _PAGE_PRESENT) || !pfn_is_ram(pfn) )
+ if ( !(l1v & _PAGE_PRESENT) || !pfn_valid(pfn) )
return;

e = page->u.inuse.domain;
@@ -1114,7 +1144,7 @@
gntref = (grant_ref_t)((val & 0xFF00) | ((ptr >> 2) & 0x00FF));

if ( unlikely(IS_XEN_HEAP_FRAME(page)) ||
- unlikely(!pfn_is_ram(pfn)) ||
+ unlikely(!pfn_valid(pfn)) ||
unlikely((e = find_domain_by_id(domid)) == NULL) )
{
MEM_LOG("Bad frame (%08lx) or bad domid (%d).\n", pfn, domid);
diff -Nru a/xen/common/grant_table.c b/xen/common/grant_table.c
--- a/xen/common/grant_table.c 2005-04-14 17:04:15 -04:00
+++ b/xen/common/grant_table.c 2005-04-14 17:04:15 -04:00
@@ -169,7 +169,7 @@

/* rmb(); */ /* not on x86 */
frame = sha->frame;
- if ( unlikely(!pfn_is_ram(frame)) ||
+ if ( unlikely(!pfn_valid(frame)) ||
unlikely(!((flags & GNTMAP_readonly) ?
get_page(&frame_table[frame], rd) :
get_page_and_type(&frame_table[frame], rd,
diff -Nru a/xen/include/asm-x86/page.h b/xen/include/asm-x86/page.h
--- a/xen/include/asm-x86/page.h 2005-04-14 17:04:15 -04:00
+++ b/xen/include/asm-x86/page.h 2005-04-14 17:04:15 -04:00
@@ -105,14 +105,7 @@
#define pfn_to_page(_pfn) (frame_table + (_pfn))
#define phys_to_page(kaddr) (frame_table + ((kaddr) >> PAGE_SHIFT))
#define virt_to_page(kaddr) (frame_table + (__pa(kaddr) >> PAGE_SHIFT))
-#define VALID_PAGE(page) ((page - frame_table) < max_mapnr)
-
-/*
- * NB. We don't currently track I/O holes in the physical RAM space.
- * For now we guess that I/O devices will be mapped in the first 1MB
- * (e.g., VGA buffers) or beyond the end of physical RAM.
- */
-#define pfn_is_ram(_pfn) (((_pfn) > 0x100) && ((_pfn) < max_page))
+#define pfn_valid(_pfn) ((_pfn) < max_page)

/* High table entries are reserved by the hypervisor. */
#define DOMAIN_ENTRIES_PER_L2_PAGETABLE \

_______________________________________________
Xen-changelog mailing list
Xen-changelog@lists.xensource.com
http://lists.xensource.com/xen-changelog