aboutsummaryrefslogtreecommitdiffstats
path: root/xenolinux-2.4.21-pre4-sparse/arch/xeno
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 /xenolinux-2.4.21-pre4-sparse/arch/xeno
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.
Diffstat (limited to 'xenolinux-2.4.21-pre4-sparse/arch/xeno')
-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
7 files changed, 263 insertions, 18 deletions
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);
+}