version 1.3.4.2, 2007/12/03 19:04:43 |
version 1.4, 2008/01/11 20:00:52 |
|
|
__KERNEL_RCSID(0, "$NetBSD$"); |
__KERNEL_RCSID(0, "$NetBSD$"); |
|
|
#include "opt_xen.h" |
#include "opt_xen.h" |
|
#include "opt_ddb.h" |
|
#include "ksyms.h" |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/systm.h> |
#include <sys/systm.h> |
Line 113 static char XBUF[256]; |
|
Line 115 static char XBUF[256]; |
|
#define PRINTF(x) printf x |
#define PRINTF(x) printf x |
#define PRINTK(x) printk x |
#define PRINTK(x) printk x |
|
|
|
/* on x86_64 kernel runs in ring 3 */ |
|
#ifdef __x86_64__ |
|
#define PG_k PG_u |
|
#else |
|
#define PG_k 0 |
|
#endif |
|
|
volatile shared_info_t *HYPERVISOR_shared_info; |
volatile shared_info_t *HYPERVISOR_shared_info; |
union start_info_union start_info_union; |
union start_info_union start_info_union; |
|
paddr_t *xpmap_phys_to_machine_mapping; |
|
|
void xen_failsafe_handler(void); |
void xen_failsafe_handler(void); |
|
|
Line 134 xen_failsafe_handler(void) |
|
Line 144 xen_failsafe_handler(void) |
|
} |
} |
|
|
|
|
#ifndef __x86_64__ |
|
void |
|
xen_update_descriptor(union descriptor *table, union descriptor *entry) |
|
{ |
|
paddr_t pa; |
|
pt_entry_t *ptp; |
|
|
|
ptp = kvtopte((vaddr_t)table); |
|
pa = (*ptp & PG_FRAME) | ((vaddr_t)table & ~PG_FRAME); |
|
if (HYPERVISOR_update_descriptor(pa, entry->raw[0], entry->raw[1])) |
|
panic("HYPERVISOR_update_descriptor failed\n"); |
|
} |
|
#endif |
|
|
|
void |
void |
xen_set_ldt(vaddr_t base, uint32_t entries) |
xen_set_ldt(vaddr_t base, uint32_t entries) |
{ |
{ |
vaddr_t va; |
vaddr_t va; |
vaddr_t end; |
vaddr_t end; |
pt_entry_t *ptp, *maptp; |
pt_entry_t *ptp; |
int s; |
int s; |
|
|
#ifdef __x86_64__ |
#ifdef __x86_64__ |
Line 165 xen_set_ldt(vaddr_t base, uint32_t entri |
|
Line 161 xen_set_ldt(vaddr_t base, uint32_t entri |
|
for (va = base; va < end; va += PAGE_SIZE) { |
for (va = base; va < end; va += PAGE_SIZE) { |
KASSERT(va >= VM_MIN_KERNEL_ADDRESS); |
KASSERT(va >= VM_MIN_KERNEL_ADDRESS); |
ptp = kvtopte(va); |
ptp = kvtopte(va); |
maptp = (pt_entry_t *)vtomach((vaddr_t)ptp); |
|
XENPRINTF(("xen_set_ldt %p %d %p %p\n", (void *)base, |
XENPRINTF(("xen_set_ldt %p %d %p %p\n", (void *)base, |
entries, ptp, maptp)); |
entries, ptp, maptp)); |
PTE_CLEARBITS(ptp, maptp, PG_RW); |
pmap_pte_clearbits(ptp, PG_RW); |
} |
} |
s = splvm(); |
s = splvm(); |
PTE_UPDATES_FLUSH(); |
|
|
|
xpq_queue_set_ldt(base, entries); |
xpq_queue_set_ldt(base, entries); |
xpq_flush_queue(); |
xpq_flush_queue(); |
splx(s); |
splx(s); |
Line 481 xpq_debug_dump() |
|
Line 474 xpq_debug_dump() |
|
#endif |
#endif |
|
|
|
|
#ifdef __x86_64__ |
|
extern volatile struct xencons_interface *xencons_interface; /* XXX */ |
extern volatile struct xencons_interface *xencons_interface; /* XXX */ |
extern struct xenstore_domain_interface *xenstore_interface; /* XXX */ |
extern struct xenstore_domain_interface *xenstore_interface; /* XXX */ |
|
|
Line 510 vaddr_t xen_pmap_bootstrap (void); |
|
Line 502 vaddr_t xen_pmap_bootstrap (void); |
|
vaddr_t |
vaddr_t |
xen_pmap_bootstrap() |
xen_pmap_bootstrap() |
{ |
{ |
int count, iocount = 0; |
int count, oldcount; |
|
long mapsize; |
|
const int l2_4_count = PTP_LEVELS - 1; |
vaddr_t bootstrap_tables, init_tables; |
vaddr_t bootstrap_tables, init_tables; |
|
|
xpmap_phys_to_machine_mapping = (paddr_t *) xen_start_info.mfn_list; |
xpmap_phys_to_machine_mapping = (paddr_t *) xen_start_info.mfn_list; |
Line 521 xen_pmap_bootstrap() |
|
Line 515 xen_pmap_bootstrap() |
|
bootstrap_tables = xen_start_info.pt_base + |
bootstrap_tables = xen_start_info.pt_base + |
(xen_start_info.nr_pt_frames * PAGE_SIZE); |
(xen_start_info.nr_pt_frames * PAGE_SIZE); |
|
|
/* Calculate how many tables we need */ |
/* |
count = TABLE_L2_ENTRIES; |
* Calculate how many space we need |
|
* first everything mapped before the Xen bootstrap tables |
|
*/ |
|
mapsize = init_tables - KERNTEXTOFF; |
|
/* after the tables we'll have: |
|
* - UAREA |
|
* - dummy user PGD (x86_64) |
|
* - HYPERVISOR_shared_info |
|
* - ISA I/O mem (if needed) |
|
*/ |
|
mapsize += UPAGES * NBPG; |
|
#ifdef __x86_64__ |
|
mapsize += NBPG; |
|
#endif |
|
mapsize += NBPG; |
|
|
#ifdef DOM0OPS |
#ifdef DOM0OPS |
if (xen_start_info.flags & SIF_INITDOMAIN) { |
if (xen_start_info.flags & SIF_INITDOMAIN) { |
/* space for ISA I/O mem */ |
/* space for ISA I/O mem */ |
iocount = IOM_SIZE / PAGE_SIZE; |
mapsize += IOM_SIZE; |
|
} |
|
#endif |
|
/* at this point mapsize doens't include the table size */ |
|
|
|
#ifdef __x86_64__ |
|
count = TABLE_L2_ENTRIES; |
|
#else |
|
count = (mapsize + (NBPD_L2 -1)) >> L2_SHIFT; |
|
#endif /* __x86_64__ */ |
|
|
|
/* now compute how many L2 pages we need exactly */ |
|
XENPRINTK(("bootstrap_final mapsize 0x%lx count %d\n", mapsize, count)); |
|
while (mapsize + (count + l2_4_count) * PAGE_SIZE + KERNTEXTOFF > |
|
((long)count << L2_SHIFT) + KERNBASE) { |
|
count++; |
} |
} |
|
#ifndef __x86_64__ |
|
nkptp[1] = count; |
#endif |
#endif |
|
|
|
/* |
|
* install bootstrap pages. We may need more L2 pages than will |
|
* have the final table here, as it's installed after the final table |
|
*/ |
|
oldcount = count; |
|
|
|
bootstrap_again: |
|
XENPRINTK(("bootstrap_again oldcount %d\n", oldcount)); |
/* |
/* |
* Xen space we'll reclaim may not be enough for our new page tables, |
* Xen space we'll reclaim may not be enough for our new page tables, |
* move bootstrap tables if necessary |
* move bootstrap tables if necessary |
*/ |
*/ |
|
if (bootstrap_tables < init_tables + ((count + l2_4_count) * PAGE_SIZE)) |
if (bootstrap_tables < init_tables + ((count+3+iocount) * PAGE_SIZE)) |
|
bootstrap_tables = init_tables + |
bootstrap_tables = init_tables + |
((count+3+iocount) * PAGE_SIZE); |
((count + l2_4_count) * PAGE_SIZE); |
|
/* make sure we have enough to map the bootstrap_tables */ |
|
if (bootstrap_tables + ((oldcount + l2_4_count) * PAGE_SIZE) > |
|
((long)oldcount << L2_SHIFT) + KERNBASE) { |
|
oldcount++; |
|
goto bootstrap_again; |
|
} |
|
|
/* Create temporary tables */ |
/* Create temporary tables */ |
xen_bootstrap_tables(xen_start_info.pt_base, bootstrap_tables, |
xen_bootstrap_tables(xen_start_info.pt_base, bootstrap_tables, |
xen_start_info.nr_pt_frames, count, 0); |
xen_start_info.nr_pt_frames, oldcount, 0); |
|
|
/* get vaddr space for the shared info and the console pages */ |
|
|
|
/* Create final tables */ |
/* Create final tables */ |
xen_bootstrap_tables(bootstrap_tables, init_tables, |
xen_bootstrap_tables(bootstrap_tables, init_tables, |
count + 3, count, 1); |
oldcount + l2_4_count, count, 1); |
|
|
return (init_tables + ((count + 3) * PAGE_SIZE)); |
/* zero out free space after tables */ |
|
memset((void *)(init_tables + ((count + l2_4_count) * PAGE_SIZE)), 0, |
|
(UPAGES + 1) * NBPG); |
|
return (init_tables + ((count + l2_4_count) * PAGE_SIZE)); |
} |
} |
|
|
|
|
Line 580 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
Line 619 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
* size of R/W area after kernel text: |
* size of R/W area after kernel text: |
* xencons_interface (if present) |
* xencons_interface (if present) |
* xenstore_interface (if present) |
* xenstore_interface (if present) |
* table pages (new_count + 3 entries) |
* table pages (new_count + (PTP_LEVELS - 1) entries) |
* UAREA |
|
* dummy user PGD |
|
* extra mappings (only when final is true): |
* extra mappings (only when final is true): |
|
* UAREA |
|
* dummy user PGD (x86_64 only)/gdt page (i386 only) |
* HYPERVISOR_shared_info |
* HYPERVISOR_shared_info |
* ISA I/O mem (if needed) |
* ISA I/O mem (if needed) |
*/ |
*/ |
map_end = new_pgd + ((new_count + 3 + UPAGES + 1) * NBPG); |
map_end = new_pgd + ((new_count + PTP_LEVELS - 1) * NBPG); |
if (final) { |
if (final) { |
HYPERVISOR_shared_info = (struct shared_info *)map_end; |
map_end += (UPAGES + 1) * NBPG; |
|
HYPERVISOR_shared_info = (shared_info_t *)map_end; |
map_end += NBPG; |
map_end += NBPG; |
} |
} |
|
/* |
|
* we always set atdevbase, as it's used by init386 to find the first |
|
* available VA. map_end is updated only if we are dom0, so |
|
* atdevbase -> atdevbase + IOM_SIZE will be mapped only in |
|
* this case. |
|
*/ |
|
if (final) |
|
atdevbase = map_end; |
#ifdef DOM0OPS |
#ifdef DOM0OPS |
if (final && (xen_start_info.flags & SIF_INITDOMAIN)) { |
if (final && (xen_start_info.flags & SIF_INITDOMAIN)) { |
/* ISA I/O mem */ |
/* ISA I/O mem */ |
atdevbase = map_end; |
|
map_end += IOM_SIZE; |
map_end += IOM_SIZE; |
} |
} |
#endif /* DOM0OPS */ |
#endif /* DOM0OPS */ |
Line 616 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
Line 663 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
bt_pgd = (pd_entry_t *) new_pgd; |
bt_pgd = (pd_entry_t *) new_pgd; |
memset (bt_pgd, 0, PAGE_SIZE); |
memset (bt_pgd, 0, PAGE_SIZE); |
avail = new_pgd + PAGE_SIZE; |
avail = new_pgd + PAGE_SIZE; |
|
#if PTP_LEVELS > 3 |
/* Install level 3 */ |
/* Install level 3 */ |
pdtpe = (pd_entry_t *) avail; |
pdtpe = (pd_entry_t *) avail; |
memset (pdtpe, 0, PAGE_SIZE); |
memset (pdtpe, 0, PAGE_SIZE); |
Line 624 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
Line 671 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
|
|
addr = ((paddr_t) pdtpe) - KERNBASE; |
addr = ((paddr_t) pdtpe) - KERNBASE; |
bt_pgd[pl4_pi(KERNTEXTOFF)] = |
bt_pgd[pl4_pi(KERNTEXTOFF)] = |
xpmap_ptom_masked(addr) | PG_u | PG_RW | PG_V; |
xpmap_ptom_masked(addr) | PG_k | PG_RW | PG_V; |
|
|
__PRINTK(("L3 va 0x%lx pa 0x%lx entry 0x%lx -> L4[0x%x]\n", |
__PRINTK(("L3 va 0x%lx pa 0x%lx entry 0x%lx -> L4[0x%x]\n", |
pdtpe, addr, bt_pgd[pl4_pi(KERNTEXTOFF)], pl4_pi(KERNTEXTOFF))); |
pdtpe, addr, bt_pgd[pl4_pi(KERNTEXTOFF)], pl4_pi(KERNTEXTOFF))); |
|
#else |
|
pdtpe = bt_pgd; |
|
#endif /* PTP_LEVELS > 3 */ |
|
|
|
#if PTP_LEVELS > 2 |
/* Level 2 */ |
/* Level 2 */ |
pde = (pd_entry_t *) avail; |
pde = (pd_entry_t *) avail; |
memset(pde, 0, PAGE_SIZE); |
memset(pde, 0, PAGE_SIZE); |
Line 636 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
Line 687 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
|
|
addr = ((paddr_t) pde) - KERNBASE; |
addr = ((paddr_t) pde) - KERNBASE; |
pdtpe[pl3_pi(KERNTEXTOFF)] = |
pdtpe[pl3_pi(KERNTEXTOFF)] = |
xpmap_ptom_masked(addr) | PG_u | PG_RW | PG_V; |
xpmap_ptom_masked(addr) | PG_k | PG_RW | PG_V; |
__PRINTK(("L2 va 0x%lx pa 0x%lx entry 0x%lx -> L3[0x%x]\n", |
__PRINTK(("L2 va 0x%lx pa 0x%lx entry 0x%lx -> L3[0x%x]\n", |
pde, addr, pdtpe[pl3_pi(KERNTEXTOFF)], pl3_pi(KERNTEXTOFF))); |
pde, addr, pdtpe[pl3_pi(KERNTEXTOFF)], pl3_pi(KERNTEXTOFF))); |
|
#else |
|
pde = bt_pgd; |
|
#endif /* PTP_LEVELS > 3 */ |
|
|
/* Level 1 */ |
/* Level 1 */ |
page = KERNTEXTOFF; |
page = KERNTEXTOFF; |
Line 663 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
Line 717 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
"va 0x%lx pte 0x%lx\n", |
"va 0x%lx pte 0x%lx\n", |
HYPERVISOR_shared_info, pte[pl1_pi(page)])); |
HYPERVISOR_shared_info, pte[pl1_pi(page)])); |
} |
} |
|
#ifdef XEN3 |
if (xpmap_ptom_masked(page - KERNBASE) == |
if (xpmap_ptom_masked(page - KERNBASE) == |
(xen_start_info.console_mfn << PAGE_SHIFT)) { |
(xen_start_info.console_mfn << PAGE_SHIFT)) { |
xencons_interface = (void *)page; |
xencons_interface = (void *)page; |
pte[pl1_pi(page)] = |
pte[pl1_pi(page)] = |
(xen_start_info.console_mfn << PAGE_SHIFT); |
(xen_start_info.console_mfn << PAGE_SHIFT); |
__PRINTK(("xencons_interface " |
__PRINTK(("xencons_interface " |
va 0x%lx pte 0x%lx\n", |
"va 0x%lx pte 0x%lx\n", |
xencons_interface, pte[pl1_pi(page)])); |
xencons_interface, pte[pl1_pi(page)])); |
} |
} |
if (xpmap_ptom_masked(page - KERNBASE) == |
if (xpmap_ptom_masked(page - KERNBASE) == |
Line 681 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
Line 736 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
"va 0x%lx pte 0x%lx\n", |
"va 0x%lx pte 0x%lx\n", |
xenstore_interface, pte[pl1_pi(page)])); |
xenstore_interface, pte[pl1_pi(page)])); |
} |
} |
|
#endif /* XEN3 */ |
#ifdef DOM0OPS |
#ifdef DOM0OPS |
if (page >= (vaddr_t)atdevbase && |
if (page >= (vaddr_t)atdevbase && |
page < (vaddr_t)atdevbase + IOM_SIZE) { |
page < (vaddr_t)atdevbase + IOM_SIZE) { |
Line 688 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
Line 744 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
IOM_BEGIN + (page - (vaddr_t)atdevbase); |
IOM_BEGIN + (page - (vaddr_t)atdevbase); |
} |
} |
#endif |
#endif |
pte[pl1_pi(page)] |= PG_u | PG_V; |
pte[pl1_pi(page)] |= PG_k | PG_V; |
if (page < text_end) { |
if (page < text_end) { |
/* map kernel text RO */ |
/* map kernel text RO */ |
pte[pl1_pi(page)] |= 0; |
pte[pl1_pi(page)] |= 0; |
Line 697 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
Line 753 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
/* map old page tables RO */ |
/* map old page tables RO */ |
pte[pl1_pi(page)] |= 0; |
pte[pl1_pi(page)] |= 0; |
} else if (page >= new_pgd && |
} else if (page >= new_pgd && |
page < new_pgd + ((new_count + 3) * PAGE_SIZE)) { |
page < new_pgd + ((new_count + PTP_LEVELS - 1) * PAGE_SIZE)) { |
/* map new page tables RO */ |
/* map new page tables RO */ |
pte[pl1_pi(page)] |= 0; |
pte[pl1_pi(page)] |= 0; |
} else { |
} else { |
/* map page RW */ |
/* map page RW */ |
pte[pl1_pi(page)] |= PG_RW; |
pte[pl1_pi(page)] |= PG_RW; |
} |
} |
if (page == old_pgd) |
if (page == old_pgd || page >= new_pgd) |
__PRINTK(("va 0x%lx pa 0x%lx |
__PRINTK(("va 0x%lx pa 0x%lx " |
"entry 0x%lx -> L1[0x%x]\n", |
"entry 0x%lx -> L1[0x%x]\n", |
page, page - KERNBASE, |
page, page - KERNBASE, |
pte[pl1_pi(page)], pl1_pi(page))); |
pte[pl1_pi(page)], pl1_pi(page))); |
Line 714 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
Line 770 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
|
|
addr = ((paddr_t) pte) - KERNBASE; |
addr = ((paddr_t) pte) - KERNBASE; |
pde[pl2_pi(cur_page)] = |
pde[pl2_pi(cur_page)] = |
xpmap_ptom_masked(addr) | PG_u | PG_RW | PG_V; |
xpmap_ptom_masked(addr) | PG_k | PG_RW | PG_V; |
__PRINTK(("L1 va 0x%lx pa 0x%lx entry 0x%lx -> L2[0x%x]\n", |
__PRINTK(("L1 va 0x%lx pa 0x%lx entry 0x%lx -> L2[0x%x]\n", |
pte, addr, pde[pl2_pi(cur_page)], pl2_pi(cur_page))); |
pte, addr, pde[pl2_pi(cur_page)], pl2_pi(cur_page))); |
/* Mark readonly */ |
/* Mark readonly */ |
Line 723 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
Line 779 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
|
|
/* Install recursive page tables mapping */ |
/* Install recursive page tables mapping */ |
bt_pgd[PDIR_SLOT_PTE] = |
bt_pgd[PDIR_SLOT_PTE] = |
xpmap_ptom_masked(new_pgd - KERNBASE) | PG_u | PG_V; |
xpmap_ptom_masked(new_pgd - KERNBASE) | PG_k | PG_V; |
__PRINTK(("bt_pgd[PDIR_SLOT_PTE] va 0x%lx pa 0x%lx entry 0x%lx\n", |
__PRINTK(("bt_pgd[PDIR_SLOT_PTE] va 0x%lx pa 0x%lx entry 0x%lx\n", |
new_pgd, new_pgd - KERNBASE, bt_pgd[PDIR_SLOT_PTE])); |
new_pgd, new_pgd - KERNBASE, bt_pgd[PDIR_SLOT_PTE])); |
|
|
/* Mark tables RO */ |
/* Mark tables RO */ |
xen_bt_set_readonly((vaddr_t) pde); |
xen_bt_set_readonly((vaddr_t) pde); |
|
#if PTP_LEVELS > 2 |
xen_bt_set_readonly((vaddr_t) pdtpe); |
xen_bt_set_readonly((vaddr_t) pdtpe); |
|
#endif |
|
#if PTP_LEVELS > 3 |
xen_bt_set_readonly(new_pgd); |
xen_bt_set_readonly(new_pgd); |
|
#endif |
/* Pin the PGD */ |
/* Pin the PGD */ |
__PRINTK(("pin PDG\n")); |
__PRINTK(("pin PDG\n")); |
xpq_queue_pin_table(xpmap_ptom_masked(new_pgd - KERNBASE)); |
xpq_queue_pin_table(xpmap_ptom_masked(new_pgd - KERNBASE)); |
|
#ifdef __i386__ |
|
/* Save phys. addr of PDP, for libkvm. */ |
|
PDPpaddr = new_pgd; |
|
#endif |
/* Switch to new tables */ |
/* Switch to new tables */ |
__PRINTK(("switch to PDG\n")); |
__PRINTK(("switch to PDG\n")); |
xpq_queue_pt_switch(xpmap_ptom_masked(new_pgd - KERNBASE)); |
xpq_queue_pt_switch(xpmap_ptom_masked(new_pgd - KERNBASE)); |
__PRINTK(("bt_pgd[PDIR_SLOT_PTE] now entry 0x%lx\n", |
__PRINTK(("bt_pgd[PDIR_SLOT_PTE] now entry 0x%lx\n", |
bt_pgd[PDIR_SLOT_PTE])); |
bt_pgd[PDIR_SLOT_PTE])); |
__PRINTK(("L4_BASE va 0x%lx\n", (long)L4_BASE)); |
|
__PRINTK(("value 0x%lx\n", *L4_BASE)); |
|
__PRINTK(("[PDIR_SLOT_PTE] 0x%lx\n", L4_BASE[PDIR_SLOT_PTE])); |
|
|
|
/* Now we can safely reclaim space taken by old tables */ |
/* Now we can safely reclaim space taken by old tables */ |
|
|
Line 758 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
Line 819 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
pde[pl2_pi(page)], addr, pte)); |
pde[pl2_pi(page)], addr, pte)); |
while (page < old_pgd + (old_count * PAGE_SIZE) && page < map_end) { |
while (page < old_pgd + (old_count * PAGE_SIZE) && page < map_end) { |
addr = xpmap_ptom(((paddr_t) pte) - KERNBASE); |
addr = xpmap_ptom(((paddr_t) pte) - KERNBASE); |
|
XENPRINTK(("addr 0x%lx pte 0x%lx *pte 0x%lx\n", |
|
addr, pte, *pte)); |
xpq_queue_pte_update((pt_entry_t *) addr, *pte | PG_RW); |
xpq_queue_pte_update((pt_entry_t *) addr, *pte | PG_RW); |
page += PAGE_SIZE; |
page += PAGE_SIZE; |
/* |
/* |
Line 770 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
Line 833 xen_bootstrap_tables (vaddr_t old_pgd, v |
|
} |
} |
|
|
|
|
void |
|
xen_set_user_pgd(paddr_t page) |
|
{ |
|
struct mmuext_op op; |
|
int s = splvm(); |
|
|
|
xpq_flush_queue(); |
|
op.cmd = MMUEXT_NEW_USER_BASEPTR; |
|
op.arg1.mfn = xpmap_phys_to_machine_mapping[page >> PAGE_SHIFT]; |
|
if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) |
|
panic("xen_set_user_pgd: failed to install new user page" |
|
" directory %lx", page); |
|
splx(s); |
|
} |
|
|
|
/* |
/* |
* Bootstrap helper functions |
* Bootstrap helper functions |
*/ |
*/ |
Line 800 xen_bt_set_readonly (vaddr_t page) |
|
Line 848 xen_bt_set_readonly (vaddr_t page) |
|
pt_entry_t entry; |
pt_entry_t entry; |
|
|
entry = xpmap_ptom_masked(page - KERNBASE); |
entry = xpmap_ptom_masked(page - KERNBASE); |
entry |= PG_u | PG_V; |
entry |= PG_k | PG_V; |
|
|
HYPERVISOR_update_va_mapping (page, entry, UVMF_INVLPG); |
HYPERVISOR_update_va_mapping (page, entry, UVMF_INVLPG); |
} |
} |
#endif /* x86_64 */ |
|
/* $NetBSD$ */ |
|
|
|
/* |
|
* Copyright (c) 2006 Mathieu Ropert <mro@adviseo.fr> |
|
* |
|
* Permission to use, copy, modify, and distribute this software for any |
|
* purpose with or without fee is hereby granted, provided that the above |
|
* copyright notice and this permission notice appear in all copies. |
|
* |
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
*/ |
|
|
|
/* |
|
* Copyright (c) 2006, 2007 Manuel Bouyer. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions |
|
* are met: |
|
* 1. Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
* notice, this list of conditions and the following disclaimer in the |
|
* documentation and/or other materials provided with the distribution. |
|
* 3. All advertising materials mentioning features or use of this software |
|
* must display the following acknowledgement: |
|
* This product includes software developed by Manuel Bouyer. |
|
* 4. The name of the author may not be used to endorse or promote products |
|
* derived from this software without specific prior written permission. |
|
* |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
* |
|
*/ |
|
|
|
/* |
|
* |
|
* Copyright (c) 2004 Christian Limpach. |
|
* All rights reserved. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions |
|
* are met: |
|
* 1. Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
* notice, this list of conditions and the following disclaimer in the |
|
* documentation and/or other materials provided with the distribution. |
|
* 3. All advertising materials mentioning features or use of this software |
|
* must display the following acknowledgement: |
|
* This product includes software developed by Christian Limpach. |
|
* 4. The name of the author may not be used to endorse or promote products |
|
* derived from this software without specific prior written permission. |
|
* |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
*/ |
|
|
|
|
|
#include <sys/cdefs.h> |
|
__KERNEL_RCSID(0, "$NetBSD$"); |
|
|
|
#include "opt_xen.h" |
|
|
|
#include <sys/param.h> |
|
#include <sys/systm.h> |
|
|
|
#include <uvm/uvm.h> |
|
|
|
#include <machine/pmap.h> |
|
#include <machine/gdt.h> |
|
#include <xen/xenfunc.h> |
|
|
|
#include <dev/isa/isareg.h> |
|
#include <machine/isa_machdep.h> |
|
|
|
#undef XENDEBUG |
|
/* #define XENDEBUG_SYNC */ |
|
/* #define XENDEBUG_LOW */ |
|
|
|
#ifdef XENDEBUG |
|
#define XENPRINTF(x) printf x |
|
#define XENPRINTK(x) printk x |
|
#define XENPRINTK2(x) /* printk x */ |
|
|
|
static char XBUF[256]; |
|
#else |
|
#define XENPRINTF(x) |
|
#define XENPRINTK(x) |
|
#define XENPRINTK2(x) |
|
#endif |
|
#define PRINTF(x) printf x |
|
#define PRINTK(x) printk x |
|
|
|
volatile shared_info_t *HYPERVISOR_shared_info; |
|
union start_info_union start_info_union; |
|
|
|
void xen_failsafe_handler(void); |
|
|
|
#ifdef XEN3 |
|
#define HYPERVISOR_mmu_update_self(req, count, success_count) \ |
|
HYPERVISOR_mmu_update((req), (count), (success_count), DOMID_SELF) |
|
#else |
|
#define HYPERVISOR_mmu_update_self(req, count, success_count) \ |
|
HYPERVISOR_mmu_update((req), (count), (success_count)) |
|
#endif |
|
|
|
void |
|
xen_failsafe_handler(void) |
|
{ |
|
|
|
panic("xen_failsafe_handler called!\n"); |
|
} |
|
|
|
|
|
#ifndef __x86_64__ |
|
void |
|
xen_update_descriptor(union descriptor *table, union descriptor *entry) |
|
{ |
|
paddr_t pa; |
|
pt_entry_t *ptp; |
|
|
|
ptp = kvtopte((vaddr_t)table); |
|
pa = (*ptp & PG_FRAME) | ((vaddr_t)table & ~PG_FRAME); |
|
if (HYPERVISOR_update_descriptor(pa, entry->raw[0], entry->raw[1])) |
|
panic("HYPERVISOR_update_descriptor failed\n"); |
|
} |
|
#endif |
|
|
|
void |
|
xen_set_ldt(vaddr_t base, uint32_t entries) |
|
{ |
|
vaddr_t va; |
|
vaddr_t end; |
|
pt_entry_t *ptp, *maptp; |
|
int s; |
|
|
|
#ifdef __x86_64__ |
#ifdef __x86_64__ |
end = base + (entries << 3); |
|
#else |
|
end = base + entries * sizeof(union descriptor); |
|
#endif |
|
|
|
for (va = base; va < end; va += PAGE_SIZE) { |
|
KASSERT(va >= VM_MIN_KERNEL_ADDRESS); |
|
ptp = kvtopte(va); |
|
maptp = (pt_entry_t *)vtomach((vaddr_t)ptp); |
|
XENPRINTF(("xen_set_ldt %p %d %p %p\n", (void *)base, |
|
entries, ptp, maptp)); |
|
PTE_CLEARBITS(ptp, maptp, PG_RW); |
|
} |
|
s = splvm(); |
|
PTE_UPDATES_FLUSH(); |
|
|
|
xpq_queue_set_ldt(base, entries); |
|
xpq_flush_queue(); |
|
splx(s); |
|
} |
|
|
|
#ifdef XENDEBUG |
|
void xpq_debug_dump(void); |
|
#endif |
|
|
|
#define XPQUEUE_SIZE 2048 |
|
static mmu_update_t xpq_queue[XPQUEUE_SIZE]; |
|
static int xpq_idx = 0; |
|
|
|
void |
|
xpq_flush_queue() |
|
{ |
|
int i, ok; |
|
|
|
XENPRINTK2(("flush queue %p entries %d\n", xpq_queue, xpq_idx)); |
|
for (i = 0; i < xpq_idx; i++) |
|
XENPRINTK2(("%d: %p %08x\n", i, (u_int)xpq_queue[i].ptr, |
|
(u_int)xpq_queue[i].val)); |
|
if (xpq_idx != 0 && |
|
HYPERVISOR_mmu_update_self(xpq_queue, xpq_idx, &ok) < 0) { |
|
printf("xpq_flush_queue: %d entries \n", xpq_idx); |
|
for (i = 0; i < xpq_idx; i++) |
|
printf("0x%016" PRIx64 ": 0x%016" PRIx64 "\n", |
|
(u_int64_t)xpq_queue[i].ptr, |
|
(u_int64_t)xpq_queue[i].val); |
|
panic("HYPERVISOR_mmu_update failed\n"); |
|
} |
|
xpq_idx = 0; |
|
} |
|
|
|
static inline void |
|
xpq_increment_idx(void) |
|
{ |
|
|
|
xpq_idx++; |
|
if (__predict_false(xpq_idx == XPQUEUE_SIZE)) |
|
xpq_flush_queue(); |
|
} |
|
|
|
void |
|
xpq_queue_machphys_update(paddr_t ma, paddr_t pa) |
|
{ |
|
XENPRINTK2(("xpq_queue_machphys_update ma=%p pa=%p\n", (void *)ma, (void *)pa)); |
|
xpq_queue[xpq_idx].ptr = ma | MMU_MACHPHYS_UPDATE; |
|
xpq_queue[xpq_idx].val = (pa - XPMAP_OFFSET) >> PAGE_SHIFT; |
|
xpq_increment_idx(); |
|
#ifdef XENDEBUG_SYNC |
|
xpq_flush_queue(); |
|
#endif |
|
} |
|
|
|
void |
|
xpq_queue_pde_update(pd_entry_t *ptr, pd_entry_t val) |
|
{ |
|
|
|
KASSERT(((paddr_t)ptr & 3) == 0); |
|
xpq_queue[xpq_idx].ptr = (paddr_t)ptr | MMU_NORMAL_PT_UPDATE; |
|
xpq_queue[xpq_idx].val = val; |
|
xpq_increment_idx(); |
|
#ifdef XENDEBUG_SYNC |
|
xpq_flush_queue(); |
|
#endif |
|
} |
|
|
|
void |
void |
xpq_queue_pte_update(pt_entry_t *ptr, pt_entry_t val) |
xen_set_user_pgd(paddr_t page) |
{ |
|
|
|
KASSERT(((paddr_t)ptr & 3) == 0); |
|
xpq_queue[xpq_idx].ptr = (paddr_t)ptr | MMU_NORMAL_PT_UPDATE; |
|
xpq_queue[xpq_idx].val = val; |
|
xpq_increment_idx(); |
|
#ifdef XENDEBUG_SYNC |
|
xpq_flush_queue(); |
|
#endif |
|
} |
|
|
|
#ifdef XEN3 |
|
void |
|
xpq_queue_pt_switch(paddr_t pa) |
|
{ |
{ |
struct mmuext_op op; |
struct mmuext_op op; |
xpq_flush_queue(); |
int s = splvm(); |
|
|
XENPRINTK2(("xpq_queue_pt_switch: %p %p\n", (void *)pa, (void *)pa)); |
|
op.cmd = MMUEXT_NEW_BASEPTR; |
|
op.arg1.mfn = pa >> PAGE_SHIFT; |
|
if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) |
|
panic("xpq_queue_pt_switch"); |
|
} |
|
|
|
void |
|
xpq_queue_pin_table(paddr_t pa) |
|
{ |
|
struct mmuext_op op; |
|
xpq_flush_queue(); |
|
|
|
XENPRINTK2(("xpq_queue_pin_table: %p %p\n", (void *)pa, (void *)pa)); |
|
op.arg1.mfn = pa >> PAGE_SHIFT; |
|
|
|
#ifdef __x86_64__ |
|
op.cmd = MMUEXT_PIN_L4_TABLE; |
|
#else |
|
op.cmd = MMUEXT_PIN_L2_TABLE; |
|
#endif |
|
if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) |
|
panic("xpq_queue_pin_table"); |
|
} |
|
|
|
void |
|
xpq_queue_unpin_table(paddr_t pa) |
|
{ |
|
struct mmuext_op op; |
|
xpq_flush_queue(); |
|
|
|
XENPRINTK2(("xpq_queue_unpin_table: %p %p\n", (void *)pa, (void *)pa)); |
|
op.arg1.mfn = pa >> PAGE_SHIFT; |
|
op.cmd = MMUEXT_UNPIN_TABLE; |
|
if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) |
|
panic("xpq_queue_unpin_table"); |
|
} |
|
|
|
void |
|
xpq_queue_set_ldt(vaddr_t va, uint32_t entries) |
|
{ |
|
struct mmuext_op op; |
|
xpq_flush_queue(); |
|
|
|
XENPRINTK2(("xpq_queue_set_ldt\n")); |
|
KASSERT(va == (va & ~PAGE_MASK)); |
|
op.cmd = MMUEXT_SET_LDT; |
|
op.arg1.linear_addr = va; |
|
op.arg2.nr_ents = entries; |
|
if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) |
|
panic("xpq_queue_set_ldt"); |
|
} |
|
|
|
void |
|
xpq_queue_tlb_flush() |
|
{ |
|
struct mmuext_op op; |
|
xpq_flush_queue(); |
|
|
|
XENPRINTK2(("xpq_queue_tlb_flush\n")); |
|
op.cmd = MMUEXT_TLB_FLUSH_LOCAL; |
|
if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) |
|
panic("xpq_queue_tlb_flush"); |
|
} |
|
|
|
void |
|
xpq_flush_cache() |
|
{ |
|
struct mmuext_op op; |
|
int s = splvm(); |
|
xpq_flush_queue(); |
|
|
|
XENPRINTK2(("xpq_queue_flush_cache\n")); |
|
op.cmd = MMUEXT_FLUSH_CACHE; |
|
if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) |
|
panic("xpq_flush_cache"); |
|
splx(s); |
|
} |
|
|
|
void |
|
xpq_queue_invlpg(vaddr_t va) |
|
{ |
|
struct mmuext_op op; |
|
xpq_flush_queue(); |
|
|
|
XENPRINTK2(("xpq_queue_invlpg %p\n", (void *)va)); |
|
op.cmd = MMUEXT_INVLPG_LOCAL; |
|
op.arg1.linear_addr = (va & ~PAGE_MASK); |
|
if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0) |
|
panic("xpq_queue_invlpg"); |
|
} |
|
|
|
int |
|
xpq_update_foreign(pt_entry_t *ptr, pt_entry_t val, int dom) |
|
{ |
|
mmu_update_t op; |
|
int ok; |
|
xpq_flush_queue(); |
|
|
|
op.ptr = (paddr_t)ptr; |
|
op.val = val; |
|
if (HYPERVISOR_mmu_update(&op, 1, &ok, dom) < 0) |
|
return EFAULT; |
|
return (0); |
|
} |
|
#else /* XEN3 */ |
|
void |
|
xpq_queue_pt_switch(paddr_t pa) |
|
{ |
|
|
|
XENPRINTK2(("xpq_queue_pt_switch: %p %p\n", (void *)pa, (void *)pa)); |
|
xpq_queue[xpq_idx].ptr = pa | MMU_EXTENDED_COMMAND; |
|
xpq_queue[xpq_idx].val = MMUEXT_NEW_BASEPTR; |
|
xpq_increment_idx(); |
|
} |
|
|
|
void |
|
xpq_queue_pin_table(paddr_t pa) |
|
{ |
|
|
|
XENPRINTK2(("xpq_queue_pin_table: %p %p\n", (void *)pa, (void *)pa)); |
|
xpq_queue[xpq_idx].ptr = pa | MMU_EXTENDED_COMMAND; |
|
xpq_queue[xpq_idx].val = MMUEXT_PIN_L2_TABLE; |
|
xpq_increment_idx(); |
|
} |
|
|
|
void |
|
xpq_queue_unpin_table(paddr_t pa) |
|
{ |
|
|
|
XENPRINTK2(("xpq_queue_unpin_table: %p %p\n", (void *)pa, (void *)pa)); |
|
xpq_queue[xpq_idx].ptr = pa | MMU_EXTENDED_COMMAND; |
|
xpq_queue[xpq_idx].val = MMUEXT_UNPIN_TABLE; |
|
xpq_increment_idx(); |
|
} |
|
|
|
void |
|
xpq_queue_set_ldt(vaddr_t va, uint32_t entries) |
|
{ |
|
|
|
XENPRINTK2(("xpq_queue_set_ldt\n")); |
|
KASSERT(va == (va & ~PAGE_MASK)); |
|
xpq_queue[xpq_idx].ptr = MMU_EXTENDED_COMMAND | va; |
|
xpq_queue[xpq_idx].val = MMUEXT_SET_LDT | (entries << MMUEXT_CMD_SHIFT); |
|
xpq_increment_idx(); |
|
} |
|
|
|
void |
|
xpq_queue_tlb_flush() |
|
{ |
|
|
|
XENPRINTK2(("xpq_queue_tlb_flush\n")); |
|
xpq_queue[xpq_idx].ptr = MMU_EXTENDED_COMMAND; |
|
xpq_queue[xpq_idx].val = MMUEXT_TLB_FLUSH; |
|
xpq_increment_idx(); |
|
} |
|
|
|
void |
|
xpq_flush_cache() |
|
{ |
|
int s = splvm(); |
|
|
|
XENPRINTK2(("xpq_queue_flush_cache\n")); |
|
xpq_queue[xpq_idx].ptr = MMU_EXTENDED_COMMAND; |
|
xpq_queue[xpq_idx].val = MMUEXT_FLUSH_CACHE; |
|
xpq_increment_idx(); |
|
xpq_flush_queue(); |
|
splx(s); |
|
} |
|
|
|
void |
|
xpq_queue_invlpg(vaddr_t va) |
|
{ |
|
|
|
XENPRINTK2(("xpq_queue_invlpg %p\n", (void *)va)); |
|
xpq_queue[xpq_idx].ptr = (va & ~PAGE_MASK) | MMU_EXTENDED_COMMAND; |
|
xpq_queue[xpq_idx].val = MMUEXT_INVLPG; |
|
xpq_increment_idx(); |
|
} |
|
|
|
int |
|
xpq_update_foreign(pt_entry_t *ptr, pt_entry_t val, int dom) |
|
{ |
|
mmu_update_t xpq_up[3]; |
|
|
|
xpq_up[0].ptr = MMU_EXTENDED_COMMAND; |
|
xpq_up[0].val = MMUEXT_SET_FOREIGNDOM | (dom << 16); |
|
xpq_up[1].ptr = (paddr_t)ptr; |
|
xpq_up[1].val = val; |
|
if (HYPERVISOR_mmu_update_self(xpq_up, 2, NULL) < 0) |
|
return EFAULT; |
|
return (0); |
|
} |
|
#endif /* XEN3 */ |
|
|
|
#ifdef XENDEBUG |
|
void |
|
xpq_debug_dump() |
|
{ |
|
int i; |
|
|
|
XENPRINTK2(("idx: %d\n", xpq_idx)); |
|
for (i = 0; i < xpq_idx; i++) { |
|
sprintf(XBUF, "%x %08x ", (u_int)xpq_queue[i].ptr, |
|
(u_int)xpq_queue[i].val); |
|
if (++i < xpq_idx) |
|
sprintf(XBUF + strlen(XBUF), "%x %08x ", |
|
(u_int)xpq_queue[i].ptr, (u_int)xpq_queue[i].val); |
|
if (++i < xpq_idx) |
|
sprintf(XBUF + strlen(XBUF), "%x %08x ", |
|
(u_int)xpq_queue[i].ptr, (u_int)xpq_queue[i].val); |
|
if (++i < xpq_idx) |
|
sprintf(XBUF + strlen(XBUF), "%x %08x ", |
|
(u_int)xpq_queue[i].ptr, (u_int)xpq_queue[i].val); |
|
XENPRINTK2(("%d: %s\n", xpq_idx, XBUF)); |
|
} |
|
} |
|
#endif |
|
|
|
|
|
#ifdef __x86_64__ |
|
extern volatile struct xencons_interface *xencons_interface; /* XXX */ |
|
extern struct xenstore_domain_interface *xenstore_interface; /* XXX */ |
|
|
|
static void xen_bt_set_readonly (vaddr_t); |
|
static void xen_bootstrap_tables (vaddr_t, vaddr_t, int, int, int); |
|
|
|
/* How many PDEs ? */ |
|
#if L2_SLOT_KERNBASE > 0 |
|
#define TABLE_L2_ENTRIES (2 * (NKL2_KIMG_ENTRIES + 1)) |
|
#else |
|
#define TABLE_L2_ENTRIES (NKL2_KIMG_ENTRIES + 1) |
|
#endif |
|
|
|
/* |
|
* Construct and switch to new pagetables |
|
* first_avail is the first vaddr we can use after |
|
* we get rid of Xen pagetables |
|
*/ |
|
|
|
vaddr_t xen_pmap_bootstrap (void); |
|
|
|
/* |
|
* Function to get rid of Xen bootstrap tables |
|
*/ |
|
|
|
vaddr_t |
|
xen_pmap_bootstrap() |
|
{ |
|
int count, iocount = 0; |
|
vaddr_t bootstrap_tables, init_tables; |
|
|
|
xpmap_phys_to_machine_mapping = (paddr_t *) xen_start_info.mfn_list; |
|
init_tables = xen_start_info.pt_base; |
|
__PRINTK(("xen_arch_pmap_bootstrap init_tables=0x%lx\n", init_tables)); |
|
|
|
/* Space after Xen boostrap tables should be free */ |
|
bootstrap_tables = xen_start_info.pt_base + |
|
(xen_start_info.nr_pt_frames * PAGE_SIZE); |
|
|
|
/* Calculate how many tables we need */ |
|
count = TABLE_L2_ENTRIES; |
|
|
|
#ifdef DOM0OPS |
|
if (xen_start_info.flags & SIF_INITDOMAIN) { |
|
/* space for ISA I/O mem */ |
|
iocount = IOM_SIZE / PAGE_SIZE; |
|
} |
|
#endif |
|
|
|
/* |
|
* Xen space we'll reclaim may not be enough for our new page tables, |
|
* move bootstrap tables if necessary |
|
*/ |
|
|
|
if (bootstrap_tables < init_tables + ((count+3+iocount) * PAGE_SIZE)) |
|
bootstrap_tables = init_tables + |
|
((count+3+iocount) * PAGE_SIZE); |
|
|
|
/* Create temporary tables */ |
|
xen_bootstrap_tables(xen_start_info.pt_base, bootstrap_tables, |
|
xen_start_info.nr_pt_frames, count, 0); |
|
|
|
/* get vaddr space for the shared info and the console pages */ |
|
|
|
/* Create final tables */ |
|
xen_bootstrap_tables(bootstrap_tables, init_tables, |
|
count + 3, count, 1); |
|
|
|
return (init_tables + ((count + 3) * PAGE_SIZE)); |
|
} |
|
|
|
|
|
/* |
|
* Build a new table and switch to it |
|
* old_count is # of old tables (including PGD, PDTPE and PDE) |
|
* new_count is # of new tables (PTE only) |
|
* we assume areas don't overlap |
|
*/ |
|
|
|
|
|
static void |
|
xen_bootstrap_tables (vaddr_t old_pgd, vaddr_t new_pgd, |
|
int old_count, int new_count, int final) |
|
{ |
|
pd_entry_t *pdtpe, *pde, *pte; |
|
pd_entry_t *cur_pgd, *bt_pgd; |
|
paddr_t addr, page; |
|
vaddr_t avail, text_end, map_end; |
|
int i; |
|
extern char __data_start; |
|
|
|
__PRINTK(("xen_bootstrap_tables(0x%lx, 0x%lx, %d, %d)\n", |
|
old_pgd, new_pgd, old_count, new_count)); |
|
text_end = ((vaddr_t)&__data_start) & ~PAGE_MASK; |
|
/* |
|
* size of R/W area after kernel text: |
|
* xencons_interface (if present) |
|
* xenstore_interface (if present) |
|
* table pages (new_count + 3 entries) |
|
* UAREA |
|
* dummy user PGD |
|
* extra mappings (only when final is true): |
|
* HYPERVISOR_shared_info |
|
* ISA I/O mem (if needed) |
|
*/ |
|
map_end = new_pgd + ((new_count + 3 + UPAGES + 1) * NBPG); |
|
if (final) { |
|
HYPERVISOR_shared_info = (struct shared_info *)map_end; |
|
map_end += NBPG; |
|
} |
|
#ifdef DOM0OPS |
|
if (final && (xen_start_info.flags & SIF_INITDOMAIN)) { |
|
/* ISA I/O mem */ |
|
atdevbase = map_end; |
|
map_end += IOM_SIZE; |
|
} |
|
#endif /* DOM0OPS */ |
|
|
|
__PRINTK(("xen_bootstrap_tables text_end 0x%lx map_end 0x%lx\n", |
|
text_end, map_end)); |
|
|
|
/* |
|
* Create bootstrap page tables |
|
* What we need: |
|
* - a PGD (level 4) |
|
* - a PDTPE (level 3) |
|
* - a PDE (level2) |
|
* - some PTEs (level 1) |
|
*/ |
|
|
|
cur_pgd = (pd_entry_t *) old_pgd; |
|
bt_pgd = (pd_entry_t *) new_pgd; |
|
memset (bt_pgd, 0, PAGE_SIZE); |
|
avail = new_pgd + PAGE_SIZE; |
|
|
|
/* Install level 3 */ |
|
pdtpe = (pd_entry_t *) avail; |
|
memset (pdtpe, 0, PAGE_SIZE); |
|
avail += PAGE_SIZE; |
|
|
|
addr = ((paddr_t) pdtpe) - KERNBASE; |
|
bt_pgd[pl4_pi(KERNTEXTOFF)] = |
|
xpmap_ptom_masked(addr) | PG_u | PG_RW | PG_V; |
|
|
|
__PRINTK(("L3 va 0x%lx pa 0x%lx entry 0x%lx -> L4[0x%x]\n", |
|
pdtpe, addr, bt_pgd[pl4_pi(KERNTEXTOFF)], pl4_pi(KERNTEXTOFF))); |
|
|
|
/* Level 2 */ |
|
pde = (pd_entry_t *) avail; |
|
memset(pde, 0, PAGE_SIZE); |
|
avail += PAGE_SIZE; |
|
|
|
addr = ((paddr_t) pde) - KERNBASE; |
|
pdtpe[pl3_pi(KERNTEXTOFF)] = |
|
xpmap_ptom_masked(addr) | PG_u | PG_RW | PG_V; |
|
__PRINTK(("L2 va 0x%lx pa 0x%lx entry 0x%lx -> L3[0x%x]\n", |
|
pde, addr, pdtpe[pl3_pi(KERNTEXTOFF)], pl3_pi(KERNTEXTOFF))); |
|
|
|
/* Level 1 */ |
|
page = KERNTEXTOFF; |
|
for (i = 0; i < new_count; i ++) { |
|
paddr_t cur_page = page; |
|
|
|
pte = (pd_entry_t *) avail; |
|
avail += PAGE_SIZE; |
|
|
|
memset(pte, 0, PAGE_SIZE); |
|
while (pl2_pi(page) == pl2_pi (cur_page)) { |
|
if (page >= map_end) { |
|
/* not mapped at all */ |
|
pte[pl1_pi(page)] = 0; |
|
page += PAGE_SIZE; |
|
continue; |
|
} |
|
pte[pl1_pi(page)] = xpmap_ptom_masked(page - KERNBASE); |
|
if (page == (vaddr_t)HYPERVISOR_shared_info) { |
|
pte[pl1_pi(page)] = xen_start_info.shared_info; |
|
__PRINTK(("HYPERVISOR_shared_info " |
|
"va 0x%lx pte 0x%lx\n", |
|
HYPERVISOR_shared_info, pte[pl1_pi(page)])); |
|
} |
|
if (xpmap_ptom_masked(page - KERNBASE) == |
|
(xen_start_info.console_mfn << PAGE_SHIFT)) { |
|
xencons_interface = (void *)page; |
|
pte[pl1_pi(page)] = |
|
(xen_start_info.console_mfn << PAGE_SHIFT); |
|
__PRINTK(("xencons_interface " |
|
va 0x%lx pte 0x%lx\n", |
|
xencons_interface, pte[pl1_pi(page)])); |
|
} |
|
if (xpmap_ptom_masked(page - KERNBASE) == |
|
(xen_start_info.store_mfn << PAGE_SHIFT)) { |
|
xenstore_interface = (void *)page; |
|
pte[pl1_pi(page)] = |
|
(xen_start_info.store_mfn << PAGE_SHIFT); |
|
__PRINTK(("xenstore_interface " |
|
"va 0x%lx pte 0x%lx\n", |
|
xenstore_interface, pte[pl1_pi(page)])); |
|
} |
|
#ifdef DOM0OPS |
|
if (page >= (vaddr_t)atdevbase && |
|
page < (vaddr_t)atdevbase + IOM_SIZE) { |
|
pte[pl1_pi(page)] = |
|
IOM_BEGIN + (page - (vaddr_t)atdevbase); |
|
} |
|
#endif |
|
pte[pl1_pi(page)] |= PG_u | PG_V; |
|
if (page < text_end) { |
|
/* map kernel text RO */ |
|
pte[pl1_pi(page)] |= 0; |
|
} else if (page >= old_pgd |
|
&& page < old_pgd + (old_count * PAGE_SIZE)) { |
|
/* map old page tables RO */ |
|
pte[pl1_pi(page)] |= 0; |
|
} else if (page >= new_pgd && |
|
page < new_pgd + ((new_count + 3) * PAGE_SIZE)) { |
|
/* map new page tables RO */ |
|
pte[pl1_pi(page)] |= 0; |
|
} else { |
|
/* map page RW */ |
|
pte[pl1_pi(page)] |= PG_RW; |
|
} |
|
if (page == old_pgd) |
|
__PRINTK(("va 0x%lx pa 0x%lx |
|
"entry 0x%lx -> L1[0x%x]\n", |
|
page, page - KERNBASE, |
|
pte[pl1_pi(page)], pl1_pi(page))); |
|
page += PAGE_SIZE; |
|
} |
|
|
|
addr = ((paddr_t) pte) - KERNBASE; |
|
pde[pl2_pi(cur_page)] = |
|
xpmap_ptom_masked(addr) | PG_u | PG_RW | PG_V; |
|
__PRINTK(("L1 va 0x%lx pa 0x%lx entry 0x%lx -> L2[0x%x]\n", |
|
pte, addr, pde[pl2_pi(cur_page)], pl2_pi(cur_page))); |
|
/* Mark readonly */ |
|
xen_bt_set_readonly((vaddr_t) pte); |
|
} |
|
|
|
/* Install recursive page tables mapping */ |
|
bt_pgd[PDIR_SLOT_PTE] = |
|
xpmap_ptom_masked(new_pgd - KERNBASE) | PG_u | PG_V; |
|
__PRINTK(("bt_pgd[PDIR_SLOT_PTE] va 0x%lx pa 0x%lx entry 0x%lx\n", |
|
new_pgd, new_pgd - KERNBASE, bt_pgd[PDIR_SLOT_PTE])); |
|
|
|
/* Mark tables RO */ |
|
xen_bt_set_readonly((vaddr_t) pde); |
|
xen_bt_set_readonly((vaddr_t) pdtpe); |
|
xen_bt_set_readonly(new_pgd); |
|
/* Pin the PGD */ |
|
__PRINTK(("pin PDG\n")); |
|
xpq_queue_pin_table(xpmap_ptom_masked(new_pgd - KERNBASE)); |
|
/* Switch to new tables */ |
|
__PRINTK(("switch to PDG\n")); |
|
xpq_queue_pt_switch(xpmap_ptom_masked(new_pgd - KERNBASE)); |
|
__PRINTK(("bt_pgd[PDIR_SLOT_PTE] now entry 0x%lx\n", |
|
bt_pgd[PDIR_SLOT_PTE])); |
|
__PRINTK(("L4_BASE va 0x%lx\n", (long)L4_BASE)); |
|
__PRINTK(("value 0x%lx\n", *L4_BASE)); |
|
__PRINTK(("[PDIR_SLOT_PTE] 0x%lx\n", L4_BASE[PDIR_SLOT_PTE])); |
|
|
|
/* Now we can safely reclaim space taken by old tables */ |
|
|
|
__PRINTK(("unpin old PDG\n")); |
|
/* Unpin old PGD */ |
|
xpq_queue_unpin_table(xpmap_ptom_masked(old_pgd - KERNBASE)); |
|
/* Mark old tables RW */ |
|
page = old_pgd; |
|
addr = (paddr_t) pde[pl2_pi(page)] & PG_FRAME; |
|
addr = xpmap_mtop(addr); |
|
pte = (pd_entry_t *) (addr + KERNBASE); |
|
pte += pl1_pi(page); |
|
__PRINTK(("*pde 0x%lx addr 0x%lx pte 0x%lx\n", |
|
pde[pl2_pi(page)], addr, pte)); |
|
while (page < old_pgd + (old_count * PAGE_SIZE) && page < map_end) { |
|
addr = xpmap_ptom(((paddr_t) pte) - KERNBASE); |
|
xpq_queue_pte_update((pt_entry_t *) addr, *pte | PG_RW); |
|
page += PAGE_SIZE; |
|
/* |
|
* Our ptes are contiguous |
|
* so it's safe to just "++" here |
|
*/ |
|
pte++; |
|
} |
|
xpq_flush_queue(); |
|
} |
|
|
|
|
|
void |
|
xen_set_user_pgd(paddr_t page) |
|
{ |
|
struct mmuext_op op; |
|
int s = splvm(); |
|
|
|
xpq_flush_queue(); |
xpq_flush_queue(); |
op.cmd = MMUEXT_NEW_USER_BASEPTR; |
op.cmd = MMUEXT_NEW_USER_BASEPTR; |
Line 1591 xen_set_user_pgd(paddr_t page) |
|
Line 868 xen_set_user_pgd(paddr_t page) |
|
" directory %lx", page); |
" directory %lx", page); |
splx(s); |
splx(s); |
} |
} |
|
#endif /* __x86_64__ */ |
/* |
|
* Bootstrap helper functions |
|
*/ |
|
|
|
/* |
|
* Mark a page readonly |
|
* XXX: assuming vaddr = paddr + KERNBASE |
|
*/ |
|
|
|
static void |
|
xen_bt_set_readonly (vaddr_t page) |
|
{ |
|
pt_entry_t entry; |
|
|
|
entry = xpmap_ptom_masked(page - KERNBASE); |
|
entry |= PG_u | PG_V; |
|
|
|
HYPERVISOR_update_va_mapping (page, entry, UVMF_INVLPG); |
|
} |
|
#endif /* x86_64 */ |
|