diff options
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(®s->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(¤t->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 a2d29aa797..2dd43ccb17 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]; }; @@ -284,4 +284,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 */ \ } |