aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>2003-04-15 17:09:30 +0000
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>2003-04-15 17:09:30 +0000
commit3067e628b29d9bbe831b41f18f342f853aa5db88 (patch)
treecbe69f0fed531fac4a6a18a99441c6f0efa97031
parent97c4f6c00218c8cf74f75a8466c4254cdfba160b (diff)
downloadxen-3067e628b29d9bbe831b41f18f342f853aa5db88.tar.gz
xen-3067e628b29d9bbe831b41f18f342f853aa5db88.tar.bz2
xen-3067e628b29d9bbe831b41f18f342f853aa5db88.zip
bitkeeper revision 1.165.1.1 (3e9c3ccaCJe7Z8jxplsENPEQ5oFIFw)
Many files: Partial checkin of virtualised LDT support.
-rw-r--r--xen/arch/i386/mm.c26
-rw-r--r--xen/arch/i386/process.c61
-rw-r--r--xen/arch/i386/traps.c165
-rw-r--r--xen/common/memory.c53
-rw-r--r--xen/include/asm-i386/desc.h5
-rw-r--r--xen/include/asm-i386/system.h44
-rw-r--r--xen/include/xeno/config.h4
-rw-r--r--xen/include/xeno/mm.h2
-rw-r--r--xen/include/xeno/sched.h26
-rw-r--r--xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/entry.S49
-rw-r--r--xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/head.S7
-rw-r--r--xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/ldt.c159
-rw-r--r--xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/process.c15
-rw-r--r--xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/setup.c3
-rw-r--r--xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/traps.c32
-rw-r--r--xenolinux-2.4.21-pre4-sparse/arch/xeno/mm/hypervisor.c16
-rw-r--r--xenolinux-2.4.21-pre4-sparse/include/asm-xeno/desc.h36
-rw-r--r--xenolinux-2.4.21-pre4-sparse/include/asm-xeno/hypervisor.h7
-rw-r--r--xenolinux-2.4.21-pre4-sparse/include/asm-xeno/mmu_context.h5
-rw-r--r--xenolinux-2.4.21-pre4-sparse/include/asm-xeno/pgalloc.h32
-rw-r--r--xenolinux-2.4.21-pre4-sparse/include/asm-xeno/pgtable.h66
-rw-r--r--xenolinux-2.4.21-pre4-sparse/include/asm-xeno/processor.h2
22 files changed, 598 insertions, 217 deletions
diff --git a/xen/arch/i386/mm.c b/xen/arch/i386/mm.c
index c18d088cfd..2eeaf928d6 100644
--- a/xen/arch/i386/mm.c
+++ b/xen/arch/i386/mm.c
@@ -116,12 +116,12 @@ long do_stack_switch(unsigned long ss, unsigned long esp)
/* Returns TRUE if given descriptor is valid for GDT or LDT. */
-static int check_descriptor(unsigned long a, unsigned long b)
+int check_descriptor(unsigned long a, unsigned long b)
{
unsigned long base, limit;
/* A not-present descriptor will always fault, so is safe. */
- if ( !(a & _SEGMENT_P) )
+ if ( !(b & _SEGMENT_P) )
goto good;
/*
@@ -130,10 +130,10 @@ static int check_descriptor(unsigned long a, unsigned long b)
* gates (consider a call gate pointing at another guestos descriptor with
* DPL 0 -- this would get the OS ring-0 privileges).
*/
- if ( (a & _SEGMENT_DPL) == 0 )
+ if ( (b & _SEGMENT_DPL) == 0 )
goto bad;
- if ( !(a & _SEGMENT_S) )
+ if ( !(b & _SEGMENT_S) )
{
/*
* System segment:
@@ -148,15 +148,15 @@ static int check_descriptor(unsigned long a, unsigned long b)
*/
/* Disallow everything but call gates. */
- if ( (a & _SEGMENT_TYPE) != 0xc00 )
+ if ( (b & _SEGMENT_TYPE) != 0xc00 )
goto bad;
/* Can't allow far jump to a Xen-private segment. */
- if ( !VALID_CODESEL(b>>16) )
+ if ( !VALID_CODESEL(a>>16) )
goto bad;
/* Reserved bits must be zero. */
- if ( (a & 0xe0) != 0 )
+ if ( (b & 0xe0) != 0 )
goto bad;
/* No base/limit check is needed for a call gate. */
@@ -164,10 +164,10 @@ static int check_descriptor(unsigned long a, unsigned long b)
}
/* Check that base/limit do not overlap Xen-private space. */
- base = (a&(0xff<<24)) | ((a&0xff)<<16) | (b>>16);
- limit = (a&0xf0000) | (b&0xffff);
+ base = (b&(0xff<<24)) | ((b&0xff)<<16) | (a>>16);
+ limit = (b&0xf0000) | (a&0xffff);
limit++; /* We add one because limit is inclusive. */
- if ( (a & _SEGMENT_G) )
+ if ( (b & _SEGMENT_G) )
limit <<= 12;
if ( ((base + limit) <= base) ||
((base + limit) >= PAGE_OFFSET) )
@@ -214,7 +214,7 @@ long do_set_gdt(unsigned long *frame_list, unsigned int entries)
/* Check all potential GDT entries in the page. */
gdt_page = map_domain_mem(frames[0] << PAGE_SHIFT);
for ( i = 0; i < 512; i++ )
- if ( !check_descriptor(gdt_page[i*2], gdt_page[i*2]+1) )
+ if ( !check_descriptor(gdt_page[i*2], gdt_page[i*2+1]) )
goto out;
unmap_domain_mem(gdt_page);
}
@@ -247,9 +247,9 @@ long do_set_gdt(unsigned long *frame_list, unsigned int entries)
flush_tlb();
/* Copy over first entries of the new GDT. */
- memcpy((void *)PERDOMAIN_VIRT_START, gdt_table, FIRST_DOMAIN_GDT_ENTRY*8);
+ memcpy((void *)GDT_VIRT_START, gdt_table, FIRST_DOMAIN_GDT_ENTRY*8);
- SET_GDT_ADDRESS(current, PERDOMAIN_VIRT_START);
+ SET_GDT_ADDRESS(current, GDT_VIRT_START);
SET_GDT_ENTRIES(current, (entries*8)-1);
__asm__ __volatile__ ("lgdt %0" : "=m" (*current->mm.gdt));
diff --git a/xen/arch/i386/process.c b/xen/arch/i386/process.c
index 05a475e11d..3affffcdc8 100644
--- a/xen/arch/i386/process.c
+++ b/xen/arch/i386/process.c
@@ -216,25 +216,6 @@ void show_regs(struct pt_regs * regs)
show_trace(&regs->esp);
}
-/*
- * No need to lock the MM as we are the last user
- */
-void release_segments(struct mm_struct *mm)
-{
-#if 0
- void * ldt = mm.context.segments;
-
- /*
- * free the LDT
- */
- if (ldt) {
- mm.context.segments = NULL;
- clear_LDT();
- vfree(ldt);
- }
-#endif
-}
-
/*
* Free current thread data structures etc..
@@ -258,48 +239,8 @@ void flush_thread(void)
void release_thread(struct task_struct *dead_task)
{
-#if 0
- if (dead_task->mm) {
- void * ldt = dead_task->mm.context.segments;
-
- // temporary debugging check
- if (ldt) {
- printk("WARNING: dead process %8s still has LDT? <%p>\n",
- dead_task->comm, ldt);
- BUG();
- }
- }
-#endif
-}
-
-/*
- * we do not have to muck with descriptors here, that is
- * done in switch_mm() as needed.
- */
-void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
-{
-#if 0
- struct mm_struct * old_mm;
- void *old_ldt, *ldt;
-
- ldt = NULL;
- old_mm = current->mm;
- if (old_mm && (old_ldt = old_mm.context.segments) != NULL) {
- /*
- * Completely new LDT, we initialize it from the parent:
- */
- ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
- if (!ldt)
- printk(KERN_WARNING "ldt allocation failed\n");
- else
- memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
- }
- new_mm.context.segments = ldt;
- new_mm.context.cpuvalid = ~0UL; /* valid on all CPU's - they can't have stale data */
-#endif
}
-
void new_thread(struct task_struct *p,
unsigned long start_pc,
unsigned long start_stack,
@@ -395,7 +336,7 @@ void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
/* Switch GDT and LDT. */
__asm__ __volatile__ ("lgdt %0" : "=m" (*next_p->mm.gdt));
-// __load_LDT(0);
+ load_LDT();
/*
* Restore %fs and %gs.
diff --git a/xen/arch/i386/traps.c b/xen/arch/i386/traps.c
index f0b15e081f..a58bfc1d73 100644
--- a/xen/arch/i386/traps.c
+++ b/xen/arch/i386/traps.c
@@ -17,7 +17,7 @@
#include <xeno/delay.h>
#include <xeno/spinlock.h>
#include <xeno/irq.h>
-
+#include <asm/domain_page.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/atomic.h>
@@ -188,22 +188,13 @@ static void inline do_trap(int trapnr, char *str,
{
struct guest_trap_bounce *gtb = guest_trap_bounce+smp_processor_id();
trap_info_t *ti;
- unsigned long addr, fixup;
+ unsigned long fixup;
if (!(regs->xcs & 3))
goto fault_in_hypervisor;
ti = current->thread.traps + trapnr;
- if ( trapnr == 14 )
- {
- /* page fault pushes %cr2 */
- gtb->flags = GTBF_TRAP_CR2;
- __asm__ __volatile__ ("movl %%cr2,%0" : "=r" (gtb->cr2) : );
- }
- else
- {
- gtb->flags = use_error_code ? GTBF_TRAP : GTBF_TRAP_NOCODE;
- }
+ gtb->flags = use_error_code ? GTBF_TRAP : GTBF_TRAP_NOCODE;
gtb->error_code = error_code;
gtb->cs = ti->cs;
gtb->eip = ti->address;
@@ -217,29 +208,10 @@ static void inline do_trap(int trapnr, char *str,
return;
}
- __asm__ __volatile__ ("movl %%cr2,%0" : "=r" (addr) : );
-
- if ( (trapnr == 14) && (addr >= PAGE_OFFSET) )
- {
- unsigned long page;
- unsigned long *pde;
- pde = (unsigned long *)idle_pg_table[smp_processor_id()];
- page = pde[addr >> L2_PAGETABLE_SHIFT];
- printk("*pde = %08lx\n", page);
- if ( page & _PAGE_PRESENT )
- {
- page &= PAGE_MASK;
- page = ((unsigned long *) __va(page))[(addr&0x3ff000)>>PAGE_SHIFT];
- printk(" *pte = %08lx\n", page);
- }
- }
-
show_registers(regs);
panic("CPU%d FATAL TRAP: vector = %d (%s)\n"
- "[error_code=%08x]\n"
- "Faulting linear address might be %08lx\n",
- smp_processor_id(), trapnr, str,
- error_code, addr);
+ "[error_code=%08x]\n",
+ smp_processor_id(), trapnr, str, error_code);
}
#define DO_ERROR_NOCODE(trapnr, str, name) \
@@ -265,14 +237,134 @@ DO_ERROR_NOCODE( 9, "coprocessor segment overrun", coprocessor_segment_overrun)
DO_ERROR(10, "invalid TSS", invalid_TSS)
DO_ERROR(11, "segment not present", segment_not_present)
DO_ERROR(12, "stack segment", stack_segment)
-DO_ERROR(14, "page fault", page_fault)
/* Vector 15 reserved by Intel */
DO_ERROR_NOCODE(16, "fpu error", coprocessor_error)
DO_ERROR(17, "alignment check", alignment_check)
DO_ERROR_NOCODE(18, "machine check", machine_check)
DO_ERROR_NOCODE(19, "simd error", simd_coprocessor_error)
-asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
+asmlinkage void do_page_fault(struct pt_regs *regs, long error_code)
+{
+ struct guest_trap_bounce *gtb = guest_trap_bounce+smp_processor_id();
+ trap_info_t *ti;
+ l2_pgentry_t *pl2e;
+ l1_pgentry_t *pl1e;
+ unsigned long addr, off, fixup, l2e, l1e, *ldt_page;
+ struct task_struct *p = current;
+ struct pfn_info *page;
+ int i;
+
+ __asm__ __volatile__ ("movl %%cr2,%0" : "=r" (addr) : );
+
+ if ( unlikely(!(regs->xcs & 3)) )
+ goto fault_in_hypervisor;
+
+ if ( unlikely(addr > PAGE_OFFSET) )
+ goto fault_in_xen_space;
+
+ bounce_fault:
+
+ if ( (regs->xcs &3) == 1 )
+ printk("Fault at %08x (%08x)\n", addr, regs->eip); /* XXX */
+
+ ti = p->thread.traps + 14;
+ gtb->flags = GTBF_TRAP_CR2; /* page fault pushes %cr2 */
+ gtb->cr2 = addr;
+ gtb->error_code = error_code;
+ gtb->cs = ti->cs;
+ gtb->eip = ti->address;
+ return;
+
+
+ fault_in_xen_space:
+
+ if ( (addr < LDT_VIRT_START) ||
+ (addr >= (LDT_VIRT_START + (p->mm.ldt_ents*LDT_ENTRY_SIZE))) )
+ goto bounce_fault;
+
+ off = addr - LDT_VIRT_START;
+ addr = p->mm.ldt_base + off;
+
+ spin_lock_irq(&p->page_lock);
+
+ pl2e = map_domain_mem(pagetable_val(p->mm.pagetable));
+ l2e = l2_pgentry_val(pl2e[l2_table_offset(addr)]);
+ unmap_domain_mem(pl2e);
+ if ( !(l2e & _PAGE_PRESENT) )
+ goto unlock_and_bounce_fault;
+
+ pl1e = map_domain_mem(l2e & PAGE_MASK);
+ l1e = l1_pgentry_val(pl1e[l1_table_offset(addr)]);
+ unmap_domain_mem(pl1e);
+ if ( !(l1e & _PAGE_PRESENT) )
+ goto unlock_and_bounce_fault;
+
+ page = frame_table + (l1e >> PAGE_SHIFT);
+ if ( (page->flags & PG_type_mask) != PGT_ldt_page )
+ {
+ if ( page->type_count != 0 )
+ { /* XXX */
+ printk("BOGO TYPE %08lx %ld\n", page->flags, page->type_count);
+ goto unlock_and_bounce_fault;
+ }
+ /* Check all potential LDT entries in the page. */
+ ldt_page = map_domain_mem(l1e & PAGE_MASK);
+ for ( i = 0; i < 512; i++ )
+ if ( !check_descriptor(ldt_page[i*2], ldt_page[i*2+1]) )
+ { /* XXX */
+ printk("Bad desc!!!!!\n");
+ goto unlock_and_bounce_fault;
+ }
+ unmap_domain_mem(ldt_page);
+ page->flags &= ~PG_type_mask;
+ page->flags |= PGT_ldt_page;
+ get_page_type(page);
+ get_page_tot(page);
+ }
+
+ p->mm.perdomain_pt[l1_table_offset(off)+16] = mk_l1_pgentry(l1e);
+
+ spin_unlock_irq(&p->page_lock);
+ return;
+
+
+ unlock_and_bounce_fault:
+
+ spin_unlock_irq(&p->page_lock);
+ goto bounce_fault;
+
+
+ fault_in_hypervisor:
+
+ if ( (fixup = search_exception_table(regs->eip)) != 0 )
+ {
+ regs->eip = fixup;
+ return;
+ }
+
+ if ( addr >= PAGE_OFFSET )
+ {
+ unsigned long page;
+ unsigned long *pde;
+ pde = (unsigned long *)idle_pg_table[smp_processor_id()];
+ page = pde[addr >> L2_PAGETABLE_SHIFT];
+ printk("*pde = %08lx\n", page);
+ if ( page & _PAGE_PRESENT )
+ {
+ page &= PAGE_MASK;
+ page = ((unsigned long *) __va(page))[(addr&0x3ff000)>>PAGE_SHIFT];
+ printk(" *pte = %08lx\n", page);
+ }
+ }
+
+ show_registers(regs);
+ panic("CPU%d FATAL PAGE FAULT\n"
+ "[error_code=%08x]\n"
+ "Faulting linear address might be %08lx\n",
+ smp_processor_id(), error_code, addr);
+}
+
+asmlinkage void do_general_protection(struct pt_regs *regs, long error_code)
{
struct guest_trap_bounce *gtb = guest_trap_bounce+smp_processor_id();
trap_info_t *ti;
@@ -315,7 +407,7 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
return;
}
}
-
+
/* Pass on GPF as is. */
ti = current->thread.traps + 13;
gtb->flags = GTBF_TRAP;
@@ -328,6 +420,7 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
if ( (fixup = search_exception_table(regs->eip)) != 0 )
{
+ printk("Hmmmm %08lx -> %08lx (%04lx)\n", regs->eip, fixup, error_code);
regs->eip = fixup;
return;
}
diff --git a/xen/common/memory.c b/xen/common/memory.c
index c39b1ae862..b7daecbf93 100644
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -176,7 +176,7 @@
#include <asm/uaccess.h>
#include <asm/domain_page.h>
-#if 0
+#if 1
#define MEM_LOG(_f, _a...) printk("DOM%d: (file=memory.c, line=%d) " _f "\n", current->domain, __LINE__, ## _a )
#else
#define MEM_LOG(_f, _a...) ((void)0)
@@ -621,10 +621,15 @@ static int mod_l1_entry(unsigned long pa, l1_pgentry_t new_l1_entry)
static int do_extended_command(unsigned long ptr, unsigned long val)
{
int err = 0;
+ unsigned int cmd = val & PGEXT_CMD_MASK;
unsigned long pfn = ptr >> PAGE_SHIFT;
struct pfn_info *page = frame_table + pfn;
- switch ( (val & PGEXT_CMD_MASK) )
+ /* 'ptr' must be in range except where it isn't a machine address. */
+ if ( (pfn >= max_page) && (cmd != PGEXT_SET_LDT) )
+ return 1;
+
+ switch ( cmd )
{
case PGEXT_PIN_L1_TABLE:
err = get_l1_table(pfn);
@@ -695,6 +700,42 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
__flush_tlb_one(val & ~PGEXT_CMD_MASK);
break;
+ case PGEXT_SET_LDT:
+ {
+ int i;
+ unsigned long ents = val >> PGEXT_CMD_SHIFT;
+ if ( ((ptr & (PAGE_SIZE-1)) != 0) ||
+ (ents > 8192) ||
+ ((ptr+ents*LDT_ENTRY_SIZE) < ptr) ||
+ ((ptr+ents*LDT_ENTRY_SIZE) > PAGE_OFFSET) )
+ {
+ err = 1;
+ MEM_LOG("Bad args to SET_LDT: ptr=%08lx, ents=%08lx", ptr, ents);
+ }
+ else if ( (current->mm.ldt_ents != ents) ||
+ (current->mm.ldt_base != ptr) )
+ {
+ if ( current->mm.ldt_ents != 0 )
+ {
+ /* Tear down the old LDT. */
+ for ( i = 16; i < 32; i++ )
+ {
+ pfn = l1_pgentry_to_pagenr(current->mm.perdomain_pt[i]);
+ if ( pfn == 0 ) continue;
+ current->mm.perdomain_pt[i] = mk_l1_pgentry(0);
+ page = frame_table + pfn;
+ put_page_type(page);
+ put_page_tot(page);
+ }
+ tlb_flush[smp_processor_id()] = 1;
+ }
+ current->mm.ldt_base = ptr;
+ current->mm.ldt_ents = ents;
+ load_LDT();
+ }
+ break;
+ }
+
default:
MEM_LOG("Invalid extended pt command 0x%08lx", val & PGEXT_CMD_MASK);
err = 1;
@@ -710,6 +751,7 @@ int do_process_page_updates(page_update_request_t *ureqs, int count)
unsigned long flags, pfn;
struct pfn_info *page;
int err = 0, i;
+ unsigned int cmd;
for ( i = 0; i < count; i++ )
{
@@ -718,8 +760,11 @@ int do_process_page_updates(page_update_request_t *ureqs, int count)
kill_domain_with_errmsg("Cannot read page update request");
}
+ cmd = req.ptr & (sizeof(l1_pgentry_t)-1);
+
+ /* All normal commands must have 'ptr' in range. */
pfn = req.ptr >> PAGE_SHIFT;
- if ( pfn >= max_page )
+ if ( (pfn >= max_page) && (cmd != PGREQ_EXTENDED_COMMAND) )
{
MEM_LOG("Page out of range (%08lx > %08lx)", pfn, max_page);
kill_domain_with_errmsg("Page update request out of range");
@@ -729,7 +774,7 @@ int do_process_page_updates(page_update_request_t *ureqs, int count)
/* Least significant bits of 'ptr' demux the operation type. */
spin_lock_irq(&current->page_lock);
- switch ( req.ptr & (sizeof(l1_pgentry_t)-1) )
+ switch ( cmd )
{
/*
* PGREQ_NORMAL: Normal update to any level of page table.
diff --git a/xen/include/asm-i386/desc.h b/xen/include/asm-i386/desc.h
index f1d11e33f7..6fc0cb7182 100644
--- a/xen/include/asm-i386/desc.h
+++ b/xen/include/asm-i386/desc.h
@@ -1,14 +1,15 @@
#ifndef __ARCH_DESC_H
#define __ARCH_DESC_H
+#define LDT_ENTRY_SIZE 8
+
#define __FIRST_TSS_ENTRY 8
#define __FIRST_LDT_ENTRY (__FIRST_TSS_ENTRY+1)
#define __TSS(n) (((n)<<1) + __FIRST_TSS_ENTRY)
#define __LDT(n) (((n)<<1) + __FIRST_LDT_ENTRY)
-#define load_TR(n) __asm__ __volatile__ ( "ltr %%ax" : : "a" (__TSS(n)<<3) )
-#define __load_LDT(n) __asm__ __volatile__ ( "lldt %%ax" : : "a" (n) )
+#define load_TR(n) __asm__ __volatile__ ("ltr %%ax" : : "a" (__TSS(n)<<3) )
/* Guest OS must provide its own code selectors, or use the one we provide. */
#define VALID_CODESEL(_s) \
diff --git a/xen/include/asm-i386/system.h b/xen/include/asm-i386/system.h
index 1ccce595d8..a24c5894ef 100644
--- a/xen/include/asm-i386/system.h
+++ b/xen/include/asm-i386/system.h
@@ -33,50 +33,6 @@ extern void FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *n
:"memory"); \
} while (0)
-#define _set_base(addr,base) do { unsigned long __pr; \
-__asm__ __volatile__ ("movw %%dx,%1\n\t" \
- "rorl $16,%%edx\n\t" \
- "movb %%dl,%2\n\t" \
- "movb %%dh,%3" \
- :"=&d" (__pr) \
- :"m" (*((addr)+2)), \
- "m" (*((addr)+4)), \
- "m" (*((addr)+7)), \
- "0" (base) \
- ); } while(0)
-
-#define _set_limit(addr,limit) do { unsigned long __lr; \
-__asm__ __volatile__ ("movw %%dx,%1\n\t" \
- "rorl $16,%%edx\n\t" \
- "movb %2,%%dh\n\t" \
- "andb $0xf0,%%dh\n\t" \
- "orb %%dh,%%dl\n\t" \
- "movb %%dl,%2" \
- :"=&d" (__lr) \
- :"m" (*(addr)), \
- "m" (*((addr)+6)), \
- "0" (limit) \
- ); } while(0)
-
-#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , (base) )
-#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , ((limit)-1)>>12 )
-
-static inline unsigned long _get_base(char * addr)
-{
- unsigned long __base;
- __asm__("movb %3,%%dh\n\t"
- "movb %2,%%dl\n\t"
- "shll $16,%%edx\n\t"
- "movw %1,%%dx"
- :"=&d" (__base)
- :"m" (*((addr)+2)),
- "m" (*((addr)+4)),
- "m" (*((addr)+7)));
- return __base;
-}
-
-#define get_base(ldt) _get_base( ((char *)&(ldt)) )
-
/*
* Load a segment. Fall back on loading the zero
* segment if something goes wrong..
diff --git a/xen/include/xeno/config.h b/xen/include/xeno/config.h
index ec92fa031c..85ad44033a 100644
--- a/xen/include/xeno/config.h
+++ b/xen/include/xeno/config.h
@@ -78,6 +78,10 @@
/* Next 4MB of virtual address space used for per-domain mappings (eg. GDT). */
#define PERDOMAIN_VIRT_START (DIRECTMAP_VIRT_END)
#define PERDOMAIN_VIRT_END (PERDOMAIN_VIRT_START + (4*1024*1024))
+#define GDT_VIRT_START (PERDOMAIN_VIRT_START)
+#define GDT_VIRT_END (GDT_VIRT_START + (64*1024))
+#define LDT_VIRT_START (GDT_VIRT_END)
+#define LDT_VIRT_END (LDT_VIRT_START + (64*1024))
/* Penultimate 4MB of virtual address space used for domain page mappings. */
#define MAPCACHE_VIRT_START (PERDOMAIN_VIRT_END)
#define MAPCACHE_VIRT_END (MAPCACHE_VIRT_START + (4*1024*1024))
diff --git a/xen/include/xeno/mm.h b/xen/include/xeno/mm.h
index f71255f971..8f75b61f5f 100644
--- a/xen/include/xeno/mm.h
+++ b/xen/include/xeno/mm.h
@@ -134,6 +134,8 @@ extern unsigned int free_pfns;
extern unsigned long max_page;
void init_frametable(unsigned long nr_pages);
+int check_descriptor(unsigned long a, unsigned long b);
+
/*
* The MPT (machine->physical mapping table) is an array of word-sized
* values, indexed on machine frame number. It is expected that guest OSes
diff --git a/xen/include/xeno/sched.h b/xen/include/xeno/sched.h
index f67e20983f..e3312a3fdb 100644
--- a/xen/include/xeno/sched.h
+++ b/xen/include/xeno/sched.h
@@ -29,8 +29,8 @@ struct mm_struct {
*/
l1_pgentry_t *perdomain_pt;
pagetable_t pagetable;
- /* Current LDT descriptor. */
- unsigned long ldt[2];
+ /* Current LDT details. */
+ unsigned long ldt_base, ldt_ents;
/* Next entry is passed to LGDT on domain switch. */
char gdt[6];
};
@@ -283,4 +283,26 @@ void cpu_idle(void); /* Idle loop. */
extern void update_process_times(int user);
+#include <asm/desc.h>
+static inline void load_LDT(void)
+{
+ unsigned int cpu;
+ struct desc_struct *desc;
+ unsigned long ents;
+
+ if ( (ents = current->mm.ldt_ents) == 0 )
+ {
+ __asm__ __volatile__ ( "lldt %%ax" : : "a" (0) );
+ }
+ else
+ {
+ cpu = smp_processor_id();
+ desc = (struct desc_struct *)GET_GDT_ADDRESS(current) + __LDT(cpu);
+ desc->a = ((LDT_VIRT_START&0xffff)<<16) | (ents*8-1);
+ desc->b = (LDT_VIRT_START&(0xff<<24)) | 0x8200 |
+ ((LDT_VIRT_START&0xff0000)>>16);
+ __asm__ __volatile__ ( "lldt %%ax" : : "a" (__LDT(cpu)<<3) );
+ }
+}
+
#endif
diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/entry.S b/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/entry.S
index 0a6a5374d1..0525e2976e 100644
--- a/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/entry.S
+++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/entry.S
@@ -133,6 +133,55 @@ ENOSYS = 38
movl $-8192, reg; \
andl %esp, reg
+ENTRY(lcall7)
+ pushfl # We get a different stack layout with call
+ pushl %eax # gates, which has to be cleaned up later..
+ SAVE_ALL
+ movl EIP(%esp),%eax # due to call gates, this is eflags, not eip..
+ movl CS(%esp),%edx # this is eip..
+ movl EFLAGS(%esp),%ecx # and this is cs..
+ movl %eax,EFLAGS(%esp) #
+ andl $~(NT_MASK|TF_MASK|DF_MASK), %eax
+ pushl %eax
+ popfl
+ movl %edx,EIP(%esp) # Now we move them to their "normal" places
+ movl %ecx,CS(%esp) #
+ movl %esp,%ebx
+ pushl %ebx
+ andl $-8192,%ebx # GET_CURRENT
+ movl exec_domain(%ebx),%edx # Get the execution domain
+ movl 4(%edx),%edx # Get the lcall7 handler for the domain
+ pushl $0x7
+ call *%edx
+ addl $4, %esp
+ popl %eax
+ jmp ret_from_sys_call
+
+ENTRY(lcall27)
+ pushfl # We get a different stack layout with call
+ pushl %eax # gates, which has to be cleaned up later..
+ SAVE_ALL
+ movl EIP(%esp),%eax # due to call gates, this is eflags, not eip..
+ movl CS(%esp),%edx # this is eip..
+ movl EFLAGS(%esp),%ecx # and this is cs..
+ movl %eax,EFLAGS(%esp) #
+ andl $~(NT_MASK|TF_MASK|DF_MASK), %eax
+ pushl %eax
+ popfl
+ movl %edx,EIP(%esp) # Now we move them to their "normal" places
+ movl %ecx,CS(%esp) #
+ movl %esp,%ebx
+ pushl %ebx
+ andl $-8192,%ebx # GET_CURRENT
+ movl exec_domain(%ebx),%edx # Get the execution domain
+ movl 4(%edx),%edx # Get the lcall7 handler for the domain
+ pushl $0x27
+ call *%edx
+ addl $4, %esp
+ popl %eax
+ jmp ret_from_sys_call
+
+
ENTRY(ret_from_fork)
pushl %ebx
call SYMBOL_NAME(schedule_tail)
diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/head.S b/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/head.S
index 86a82b13dc..a89fd8eda4 100644
--- a/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/head.S
+++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/head.S
@@ -57,11 +57,14 @@ ENTRY(stack_start)
ENTRY(empty_zero_page)
.org 0x2000
+ENTRY(default_ldt)
+
+.org 0x3000
ENTRY(cpu0_pte_quicklist)
-.org 0x2400
+.org 0x3400
ENTRY(cpu0_pgd_quicklist)
-.org 0x2800
+.org 0x3800
ENTRY(stext)
ENTRY(_stext)
diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/ldt.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/ldt.c
index 6c93943036..ca89b694bd 100644
--- a/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/ldt.c
+++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/ldt.c
@@ -9,18 +9,161 @@
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/vmalloc.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/ldt.h>
+#include <asm/desc.h>
/*
- * XXX KAF (28/7/02): This stuff is only used for DOS emulation, and is
- * the default way of finding current TCB in linuxthreads. Supporting
- * table update svia the hypervisor is feasible, but a hassle: for now,
- * recompiling linuxthreads is the most sensible option.
- *
- * Oh, this may become an issue depending on what JVM we use for
- * running the xeno-daemon.
+ * read_ldt() is not really atomic - this is not a problem since
+ * synchronization of reads and writes done to the LDT has to be
+ * assured by user-space anyway. Writes are atomic, to protect
+ * the security checks done on new descriptors.
*/
+static int read_ldt(void * ptr, unsigned long bytecount)
+{
+ int err;
+ unsigned long size;
+ struct mm_struct * mm = current->mm;
+
+ err = 0;
+ if (!mm->context.segments)
+ goto out;
+
+ size = LDT_ENTRIES*LDT_ENTRY_SIZE;
+ if (size > bytecount)
+ size = bytecount;
+
+ err = size;
+ if (copy_to_user(ptr, mm->context.segments, size))
+ err = -EFAULT;
+ out:
+ return err;
+}
+
+static int read_default_ldt(void * ptr, unsigned long bytecount)
+{
+ int err;
+ unsigned long size;
+ void *address;
+
+ err = 0;
+ address = &default_ldt[0];
+ size = sizeof(struct desc_struct);
+ if (size > bytecount)
+ size = bytecount;
+
+ err = size;
+ if (copy_to_user(ptr, address, size))
+ err = -EFAULT;
+
+ return err;
+}
+
+static int write_ldt(void * ptr, unsigned long bytecount, int oldmode)
+{
+ struct mm_struct * mm = current->mm;
+ __u32 entry_1, entry_2, *lp;
+ unsigned long phys_lp;
+ int error;
+ struct modify_ldt_ldt_s ldt_info;
+
+ error = -EINVAL;
+ if (bytecount != sizeof(ldt_info))
+ goto out;
+ error = -EFAULT;
+ if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info)))
+ goto out;
+
+ error = -EINVAL;
+ if (ldt_info.entry_number >= LDT_ENTRIES)
+ goto out;
+ if (ldt_info.contents == 3) {
+ if (oldmode)
+ goto out;
+ if (ldt_info.seg_not_present == 0)
+ goto out;
+ }
+
+ down_write(&mm->mmap_sem);
+ if (!mm->context.segments) {
+ void * segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
+ error = -ENOMEM;
+ if (!segments)
+ goto out_unlock;
+ memset(segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
+ make_pages_readonly(segments, (LDT_ENTRIES*LDT_ENTRY_SIZE)/PAGE_SIZE);
+ wmb();
+ mm->context.segments = segments;
+ mm->context.cpuvalid = 1UL << smp_processor_id();
+ load_LDT(mm);
+ flush_page_update_queue();
+ }
+
+ lp = (__u32 *)((ldt_info.entry_number<<3) + (char *)mm->context.segments);
+ phys_lp = arbitrary_virt_to_phys(lp);
+
+ /* Allow LDTs to be cleared by the user. */
+ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
+ if (oldmode ||
+ (ldt_info.contents == 0 &&
+ ldt_info.read_exec_only == 1 &&
+ ldt_info.seg_32bit == 0 &&
+ ldt_info.limit_in_pages == 0 &&
+ ldt_info.seg_not_present == 1 &&
+ ldt_info.useable == 0 )) {
+ entry_1 = 0;
+ entry_2 = 0;
+ goto install;
+ }
+ }
+
+ entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
+ (ldt_info.limit & 0x0ffff);
+ entry_2 = (ldt_info.base_addr & 0xff000000) |
+ ((ldt_info.base_addr & 0x00ff0000) >> 16) |
+ (ldt_info.limit & 0xf0000) |
+ ((ldt_info.read_exec_only ^ 1) << 9) |
+ (ldt_info.contents << 10) |
+ ((ldt_info.seg_not_present ^ 1) << 15) |
+ (ldt_info.seg_32bit << 22) |
+ (ldt_info.limit_in_pages << 23) |
+ 0x7000;
+ if (!oldmode)
+ entry_2 |= (ldt_info.useable << 20);
+
+ /* Install the new entry ... */
+ install:
+ HYPERVISOR_update_descriptor(phys_lp, entry_1, entry_2);
+ error = 0;
+
+ out_unlock:
+ up_write(&mm->mmap_sem);
+ out:
+ return error;
+}
asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
{
- return -ENOSYS;
+ int ret = -ENOSYS;
+
+ switch (func) {
+ case 0:
+ ret = read_ldt(ptr, bytecount);
+ break;
+ case 1:
+ ret = write_ldt(ptr, bytecount, 1);
+ break;
+ case 2:
+ ret = read_default_ldt(ptr, bytecount);
+ break;
+ case 0x11:
+ ret = write_ldt(ptr, bytecount, 0);
+ break;
+ }
+ return ret;
}
diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/process.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/process.c
index 32ce1a66ab..4dc1273c7b 100644
--- a/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/process.c
+++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/process.c
@@ -140,6 +140,8 @@ void release_segments(struct mm_struct *mm)
if (ldt) {
mm->context.segments = NULL;
clear_LDT();
+ make_pages_writeable(ldt, (LDT_ENTRIES*LDT_ENTRY_SIZE)/PAGE_SIZE);
+ flush_page_update_queue();
vfree(ldt);
}
}
@@ -225,10 +227,15 @@ void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
* Completely new LDT, we initialize it from the parent:
*/
ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
- if (!ldt)
+ if ( ldt == NULL )
+ {
printk(KERN_WARNING "ldt allocation failed\n");
+ }
else
+ {
memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
+ make_pages_readonly(ldt, (LDT_ENTRIES*LDT_ENTRY_SIZE)/PAGE_SIZE);
+ }
}
new_mm->context.segments = ldt;
new_mm->context.cpuvalid = ~0UL; /* valid on all CPU's - they can't have stale data */
@@ -335,6 +342,10 @@ void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
struct thread_struct *prev = &prev_p->thread,
*next = &next_p->thread;
+ __cli();
+
+ MULTICALL_flush_page_update_queue();
+
/*
* This is basically 'unlazy_fpu', except that we queue a multicall to
* indicate FPU task switch, rather than synchronously trapping to Xen.
@@ -356,7 +367,7 @@ void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
/* EXECUTE ALL TASK SWITCH XEN SYSCALLS AT THIS POINT. */
execute_multicall_list();
- sti(); /* matches 'cli' in switch_mm() */
+ __sti();
/*
* Save away %fs and %gs. No need to save %es and %ds, as
diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/setup.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/setup.c
index 6ac4ff242e..b3fa27fb11 100644
--- a/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/setup.c
+++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/setup.c
@@ -968,6 +968,9 @@ void __init cpu_init (void)
HYPERVISOR_stack_switch(__KERNEL_DS, current->thread.esp0);
+ load_LDT(&init_mm);
+ flush_page_update_queue();
+
/* Force FPU initialization. */
current->flags &= ~PF_USEDFPU;
current->used_math = 0;
diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/traps.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/traps.c
index da7cd7413e..a10c07a0ae 100644
--- a/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/traps.c
+++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/traps.c
@@ -42,6 +42,8 @@
#include <linux/module.h>
asmlinkage int system_call(void);
+asmlinkage void lcall7(void);
+asmlinkage void lcall27(void);
asmlinkage void divide_error(void);
asmlinkage void debug(void);
@@ -530,6 +532,26 @@ asmlinkage void math_state_restore(struct pt_regs regs)
current->flags |= PF_USEDFPU; /* So we fnsave on switch_to() */
}
+
+#define _set_gate(gate_addr,type,dpl,addr) \
+do { \
+ int __d0, __d1; \
+ __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
+ "movw %4,%%dx\n\t" \
+ "movl %%eax,%0\n\t" \
+ "movl %%edx,%1" \
+ :"=m" (*((long *) (gate_addr))), \
+ "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
+ :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
+ "3" ((char *) (addr)),"2" (__KERNEL_CS << 16)); \
+} while (0)
+
+static void __init set_call_gate(void *a, void *addr)
+{
+ _set_gate(a,12,3,addr);
+}
+
+
static trap_info_t trap_table[] = {
{ 0, 0, __KERNEL_CS, (unsigned long)divide_error },
{ 1, 0, __KERNEL_CS, (unsigned long)debug },
@@ -561,5 +583,15 @@ void __init trap_init(void)
{
HYPERVISOR_set_trap_table(trap_table);
HYPERVISOR_set_fast_trap(SYSCALL_VECTOR);
+
+ /*
+ * The default LDT is a single-entry callgate to lcall7 for iBCS and a
+ * callgate to lcall27 for Solaris/x86 binaries.
+ */
+ clear_page(&default_ldt[0]);
+ set_call_gate(&default_ldt[0],lcall7);
+ set_call_gate(&default_ldt[4],lcall27);
+ __make_page_readonly(&default_ldt[0]);
+
cpu_init();
}
diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/mm/hypervisor.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/mm/hypervisor.c
index 93554c3420..d67ad51dc5 100644
--- a/xenolinux-2.4.21-pre4-sparse/arch/xeno/mm/hypervisor.c
+++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/mm/hypervisor.c
@@ -81,12 +81,6 @@ static void DEBUG_disallow_pt_read(unsigned long pa)
/*
- * This is the current pagetable base pointer, which is updated
- * on context switch.
- */
-unsigned long pt_baseptr;
-
-/*
* MULTICALL_flush_page_update_queue:
* This is a version of the flush which queues as part of a multicall.
*/
@@ -232,3 +226,13 @@ void queue_pte_unpin(unsigned long ptr)
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
+
+void queue_set_ldt(unsigned long ptr, unsigned long len)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&update_lock, flags);
+ update_queue[idx].ptr = PGREQ_EXTENDED_COMMAND | ptr;
+ update_queue[idx].val = PGEXT_SET_LDT | (len << PGEXT_CMD_SHIFT);
+ increment_index();
+ spin_unlock_irqrestore(&update_lock, flags);
+}
diff --git a/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/desc.h b/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/desc.h
index 1920de026a..c417cbe807 100644
--- a/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/desc.h
+++ b/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/desc.h
@@ -3,9 +3,37 @@
#include <asm/ldt.h>
-#define __LDT(_X) (0)
+#ifndef __ASSEMBLY__
-#define clear_LDT() ((void)0)
-#define load_LDT(_mm) ((void)0)
+struct desc_struct {
+ unsigned long a,b;
+};
-#endif
+struct Xgt_desc_struct {
+ unsigned short size;
+ unsigned long address __attribute__((packed));
+};
+
+extern struct desc_struct default_ldt[];
+
+static inline void clear_LDT(void)
+{
+ queue_set_ldt((unsigned long)&default_ldt[0], 5);
+}
+
+static inline void load_LDT(struct mm_struct *mm)
+{
+ void *segments = mm->context.segments;
+ int count = LDT_ENTRIES;
+
+ if (!segments) {
+ segments = &default_ldt[0];
+ count = 5;
+ }
+
+ queue_set_ldt((unsigned long)segments, count);
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ARCH_DESC_H__ */
diff --git a/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/hypervisor.h b/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/hypervisor.h
index 35de4c20eb..b7dfb52e20 100644
--- a/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/hypervisor.h
+++ b/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/hypervisor.h
@@ -11,6 +11,7 @@
#include <asm/hypervisor-ifs/hypervisor-if.h>
#include <asm/ptrace.h>
+#include <asm/page.h>
/* arch/xeno/kernel/setup.c */
union start_info_union
@@ -42,7 +43,7 @@ void queue_pgd_pin(unsigned long ptr);
void queue_pgd_unpin(unsigned long ptr);
void queue_pte_pin(unsigned long ptr);
void queue_pte_unpin(unsigned long ptr);
-
+void queue_set_ldt(unsigned long ptr, unsigned long bytes);
#define PT_UPDATE_DEBUG 0
#if PT_UPDATE_DEBUG > 0
@@ -119,6 +120,10 @@ extern page_update_debug_t update_debug_queue[];
printk("PTE UNPIN %s %d: %08lx\n", __FILE__, __LINE__, (_p)); \
queue_pte_unpin(_p); \
})
+#define queue_set_ldt(_p,_l) ({ \
+ printk("SETL LDT %s %d: %08lx %d\n", __FILE__, __LINE__, (_p), (_l)); \
+ queue_set_ldt((_p), (_l)); \
+})
#endif
void _flush_page_update_queue(void);
diff --git a/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/mmu_context.h b/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/mmu_context.h
index ad07796f95..cdf5319f48 100644
--- a/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/mmu_context.h
+++ b/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/mmu_context.h
@@ -34,7 +34,6 @@ extern pgd_t *cur_pgd;
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu)
{
- cli(); /* protect flush_update_queue multicall */
if (prev != next) {
/* stop flush ipis for the previous mm */
clear_bit(cpu, &prev->cpu_vm_mask);
@@ -52,7 +51,6 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, str
/* Re-load page tables */
cur_pgd = next->pgd;
queue_pt_switch(__pa(cur_pgd));
- MULTICALL_flush_page_update_queue();
}
#ifdef CONFIG_SMP
else {
@@ -74,8 +72,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, str
#define activate_mm(prev, next) \
do { \
switch_mm((prev),(next),NULL,smp_processor_id()); \
- execute_multicall_list(); \
- sti(); /* matches 'cli' in switch_mm() */ \
+ flush_page_update_queue(); \
} while ( 0 )
#endif
diff --git a/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/pgalloc.h b/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/pgalloc.h
index 6dec534017..49d6e30b2a 100644
--- a/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/pgalloc.h
+++ b/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/pgalloc.h
@@ -73,19 +73,13 @@ out_oom:
static inline pgd_t *get_pgd_slow(void)
{
pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
- pgd_t *kpgd;
- pmd_t *kpmd;
- pte_t *kpte;
if (pgd) {
memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
memcpy(pgd + USER_PTRS_PER_PGD,
init_mm.pgd + USER_PTRS_PER_PGD,
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
- kpgd = pgd_offset_k((unsigned long)pgd);
- kpmd = pmd_offset(kpgd, (unsigned long)pgd);
- kpte = pte_offset(kpmd, (unsigned long)pgd);
- queue_l1_entry_update(__pa(kpte), (*(unsigned long *)kpte)&~_PAGE_RW);
+ __make_page_readonly(pgd);
queue_pgd_pin(__pa(pgd));
}
@@ -117,14 +111,8 @@ static inline void free_pgd_slow(pgd_t *pgd)
free_page((unsigned long)__va(pgd_val(pgd[i])-1));
kmem_cache_free(pae_pgd_cachep, pgd);
#else
- pgd_t *kpgd;
- pmd_t *kpmd;
- pte_t *kpte;
queue_pgd_unpin(__pa(pgd));
- kpgd = pgd_offset_k((unsigned long)pgd);
- kpmd = pmd_offset(kpgd, (unsigned long)pgd);
- kpte = pte_offset(kpmd, (unsigned long)pgd);
- queue_l1_entry_update(__pa(kpte), (*(unsigned long *)kpte)|_PAGE_RW);
+ __make_page_writeable(pgd);
free_page((unsigned long)pgd);
#endif
}
@@ -141,18 +129,12 @@ static inline void free_pgd_fast(pgd_t *pgd)
static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
{
pte_t *pte;
- pgd_t *kpgd;
- pmd_t *kpmd;
- pte_t *kpte;
pte = (pte_t *) __get_free_page(GFP_KERNEL);
if (pte)
{
clear_page(pte);
- kpgd = pgd_offset_k((unsigned long)pte);
- kpmd = pmd_offset(kpgd, (unsigned long)pte);
- kpte = pte_offset(kpmd, (unsigned long)pte);
- queue_l1_entry_update(__pa(kpte), (*(unsigned long *)kpte)&~_PAGE_RW);
+ __make_page_readonly(pte);
queue_pte_pin(__pa(pte));
}
return pte;
@@ -172,14 +154,8 @@ static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm,
static __inline__ void pte_free_slow(pte_t *pte)
{
- pgd_t *kpgd;
- pmd_t *kpmd;
- pte_t *kpte;
queue_pte_unpin(__pa(pte));
- kpgd = pgd_offset_k((unsigned long)pte);
- kpmd = pmd_offset(kpgd, (unsigned long)pte);
- kpte = pte_offset(kpmd, (unsigned long)pte);
- queue_l1_entry_update(__pa(kpte), (*(unsigned long *)kpte)|_PAGE_RW);
+ __make_page_writeable(pte);
free_page((unsigned long)pte);
}
diff --git a/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/pgtable.h b/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/pgtable.h
index 3cc0e90ae5..0f914c7c42 100644
--- a/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/pgtable.h
+++ b/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/pgtable.h
@@ -99,6 +99,7 @@ extern void pgtable_cache_init(void);
#ifndef __ASSEMBLY__
/* 4MB is just a nice "safety zone". Also, we align to a fresh pde. */
#define VMALLOC_OFFSET (4*1024*1024)
+extern void * high_memory;
#define VMALLOC_START (((unsigned long) high_memory + 2*VMALLOC_OFFSET-1) & \
~(VMALLOC_OFFSET-1))
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
@@ -291,6 +292,71 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
struct page;
int change_page_attr(struct page *, int, pgprot_t prot);
+static inline void __make_page_readonly(void *va)
+{
+ pgd_t *pgd = pgd_offset_k((unsigned long)va);
+ pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
+ pte_t *pte = pte_offset(pmd, (unsigned long)va);
+ queue_l1_entry_update(__pa(pte), (*(unsigned long *)pte)&~_PAGE_RW);
+}
+
+static inline void __make_page_writeable(void *va)
+{
+ pgd_t *pgd = pgd_offset_k((unsigned long)va);
+ pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
+ pte_t *pte = pte_offset(pmd, (unsigned long)va);
+ queue_l1_entry_update(__pa(pte), (*(unsigned long *)pte)|_PAGE_RW);
+}
+
+static inline void make_page_readonly(void *va)
+{
+ pgd_t *pgd = pgd_offset_k((unsigned long)va);
+ pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
+ pte_t *pte = pte_offset(pmd, (unsigned long)va);
+ queue_l1_entry_update(__pa(pte), (*(unsigned long *)pte)&~_PAGE_RW);
+ if ( (unsigned long)va >= VMALLOC_START )
+ __make_page_readonly(machine_to_virt(
+ *(unsigned long *)pte&PAGE_MASK));
+}
+
+static inline void make_page_writeable(void *va)
+{
+ pgd_t *pgd = pgd_offset_k((unsigned long)va);
+ pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
+ pte_t *pte = pte_offset(pmd, (unsigned long)va);
+ queue_l1_entry_update(__pa(pte), (*(unsigned long *)pte)|_PAGE_RW);
+ if ( (unsigned long)va >= VMALLOC_START )
+ __make_page_writeable(machine_to_virt(
+ *(unsigned long *)pte&PAGE_MASK));
+}
+
+static inline void make_pages_readonly(void *va, unsigned int nr)
+{
+ while ( nr-- != 0 )
+ {
+ make_page_readonly(va);
+ va = (void *)((unsigned long)va + PAGE_SIZE);
+ }
+}
+
+static inline void make_pages_writeable(void *va, unsigned int nr)
+{
+ while ( nr-- != 0 )
+ {
+ make_page_writeable(va);
+ va = (void *)((unsigned long)va + PAGE_SIZE);
+ }
+}
+
+static inline unsigned long arbitrary_virt_to_phys(void *va)
+{
+ pgd_t *pgd = pgd_offset_k((unsigned long)va);
+ pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
+ pte_t *pte = pte_offset(pmd, (unsigned long)va);
+ unsigned long pa = (*(unsigned long *)pte) & PAGE_MASK;
+ return pa | ((unsigned long)va & (PAGE_SIZE-1));
+}
+
#endif /* !__ASSEMBLY__ */
/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
diff --git a/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/processor.h b/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/processor.h
index f21e0d7f2d..86b0020c23 100644
--- a/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/processor.h
+++ b/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/processor.h
@@ -381,7 +381,7 @@ struct thread_struct {
0,0,0,0, /* esp,ebp,esi,edi */ \
0,0,0,0,0,0, /* es,cs,ss */ \
0,0,0,0,0,0, /* ds,fs,gs */ \
- __LDT(0),0, /* ldt */ \
+ 0,0, /* ldt */ \
0, INVALID_IO_BITMAP_OFFSET, /* tace, bitmap */ \
{~0, } /* ioperm */ \
}