aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsmh22@boulderdash.cl.cam.ac.uk <smh22@boulderdash.cl.cam.ac.uk>2002-12-10 14:45:04 +0000
committersmh22@boulderdash.cl.cam.ac.uk <smh22@boulderdash.cl.cam.ac.uk>2002-12-10 14:45:04 +0000
commit39b0acbcc9fadbad4d8a96ef934a8131bda99c5d (patch)
treecac1fb7fe697a64def893c8dbc52342a99cda177
parent597358ac038a754c99d1b399f3ae2455e7fbe8e4 (diff)
parent2d79667816dfa2dff25df09bdfa01d2bdb33e923 (diff)
downloadxen-39b0acbcc9fadbad4d8a96ef934a8131bda99c5d.tar.gz
xen-39b0acbcc9fadbad4d8a96ef934a8131bda99c5d.tar.bz2
xen-39b0acbcc9fadbad4d8a96ef934a8131bda99c5d.zip
bitkeeper revision 1.10 (3df5fdf08iqVVKnjFD3pfq_hggDi2Q)
Merge boulderdash.cl.cam.ac.uk:/usr/groups/xeno/BK/xeno into boulderdash.cl.cam.ac.uk:/local/scratch/smh22/xeno.bk
-rw-r--r--BitKeeper/etc/logging_ok1
-rw-r--r--xen-2.4.16/arch/i386/entry.S5
-rw-r--r--xen-2.4.16/arch/i386/i387.c26
-rw-r--r--xen-2.4.16/arch/i386/setup.c3
-rw-r--r--xen-2.4.16/arch/i386/traps.c176
-rw-r--r--xen-2.4.16/include/hypervisor-ifs/hypervisor-if.h2
-rw-r--r--xenolinux-2.4.16-sparse/arch/xeno/kernel/process.c26
-rw-r--r--xenolinux-2.4.16-sparse/arch/xeno/kernel/signal.c8
-rw-r--r--xenolinux-2.4.16-sparse/arch/xeno/kernel/traps.c55
-rw-r--r--xenolinux-2.4.16-sparse/include/asm-xeno/hypervisor.h22
10 files changed, 233 insertions, 91 deletions
diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok
index f7137dd8c5..c3ebee9a35 100644
--- a/BitKeeper/etc/logging_ok
+++ b/BitKeeper/etc/logging_ok
@@ -1,4 +1,5 @@
akw27@boulderdash.cl.cam.ac.uk
+kaf24@labyrinth.cl.cam.ac.uk
kaf24@plym.cl.cam.ac.uk
kaf24@striker.cl.cam.ac.uk
smh22@boulderdash.cl.cam.ac.uk
diff --git a/xen-2.4.16/arch/i386/entry.S b/xen-2.4.16/arch/i386/entry.S
index 996c1eb82f..ecd878acd1 100644
--- a/xen-2.4.16/arch/i386/entry.S
+++ b/xen-2.4.16/arch/i386/entry.S
@@ -302,6 +302,9 @@ FAULT11:movl %eax,4(%esi)
movl EFLAGS+4(%esp),%eax
FAULT12:movl %eax,8(%esi)
/* Rewrite our stack frame and return to ring 1. */
+ /* IA32 Ref. Vol. 3: TF, VM, RF and NT flags are cleared on trap. */
+ andl $0xfffcbeff,%eax
+ movl %eax,EFLAGS+4(%esp)
movl %ds,OLDSS+4(%esp)
movl %esi,OLDESP+4(%esp)
movzwl %es:GTB_CS(%edx),%eax
@@ -521,6 +524,8 @@ ENTRY(hypervisor_call_table)
.long SYMBOL_NAME(kill_domain)
.long SYMBOL_NAME(do_dom0_op)
.long SYMBOL_NAME(do_network_op)
+ .long SYMBOL_NAME(do_set_debugreg)
+ .long SYMBOL_NAME(do_get_debugreg)
.rept NR_syscalls-(.-hypervisor_call_table)/4
.long SYMBOL_NAME(sys_ni_syscall)
.endr
diff --git a/xen-2.4.16/arch/i386/i387.c b/xen-2.4.16/arch/i386/i387.c
index dc94cc1dad..fe34ff16f5 100644
--- a/xen-2.4.16/arch/i386/i387.c
+++ b/xen-2.4.16/arch/i386/i387.c
@@ -22,20 +22,26 @@ void init_fpu(void)
static inline void __save_init_fpu( struct task_struct *tsk )
{
- if ( cpu_has_fxsr ) {
- asm volatile( "fxsave %0 ; fnclex"
- : "=m" (tsk->thread.i387.fxsave) );
- } else {
- asm volatile( "fnsave %0 ; fwait"
- : "=m" (tsk->thread.i387.fsave) );
- }
- tsk->flags &= ~PF_USEDFPU;
+ if ( cpu_has_fxsr ) {
+ asm volatile( "fxsave %0 ; fnclex"
+ : "=m" (tsk->thread.i387.fxsave) );
+ } else {
+ asm volatile( "fnsave %0 ; fwait"
+ : "=m" (tsk->thread.i387.fsave) );
+ }
+ tsk->flags &= ~PF_USEDFPU;
}
void save_init_fpu( struct task_struct *tsk )
{
- __save_init_fpu(tsk);
- stts();
+ /*
+ * The guest OS may have set the 'virtual STTS' flag.
+ * This causes us to set the real flag, so we'll need
+ * to temporarily clear it while saving f-p state.
+ */
+ if ( tsk->flags & PF_GUEST_STTS ) clts();
+ __save_init_fpu(tsk);
+ stts();
}
void restore_fpu( struct task_struct *tsk )
diff --git a/xen-2.4.16/arch/i386/setup.c b/xen-2.4.16/arch/i386/setup.c
index f9163148ed..3cb11f6b05 100644
--- a/xen-2.4.16/arch/i386/setup.c
+++ b/xen-2.4.16/arch/i386/setup.c
@@ -193,6 +193,9 @@ void __init cpu_init(void)
/* No nested task. */
__asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
+ /* Ensure FPU gets initialised for each domain. */
+ stts();
+
/* Set up and load the per-CPU TSS and LDT. */
t->ss0 = __HYPERVISOR_DS;
t->esp0 = current->thread.esp0;
diff --git a/xen-2.4.16/arch/i386/traps.c b/xen-2.4.16/arch/i386/traps.c
index e84690ad1a..9c9948fe3f 100644
--- a/xen-2.4.16/arch/i386/traps.c
+++ b/xen-2.4.16/arch/i386/traps.c
@@ -273,7 +273,26 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
if (!(regs->xcs & 3) || (error_code & 1))
goto gp_in_kernel;
- if ( (error_code & 2) )
+ /*
+ * Cunning trick to allow arbitrary "INT n" handling.
+ *
+ * We set DPL == 0 on all vectors in the IDT. This prevents any INT <n>
+ * instruction from trapping to the appropriate vector, when that might not
+ * be expected by Xen or the guest OS. For example, that entry might be for
+ * a fault handler (unlike traps, faults don't increment EIP), or might
+ * expect an error code on the stack (which a software trap never
+ * provides), or might be a hardware interrupt handler that doesn't like
+ * being called spuriously.
+ *
+ * Instead, a GPF occurs with the faulting IDT vector in the error code.
+ * Bit 1 is set to indicate that an IDT entry caused the fault.
+ * Bit 0 is clear to indicate that it's a software fault, not hardware.
+ *
+ * NOTE: Vectors 3 and 4 are dealt with from their own handler. This is okay
+ * because they can only be triggered by an explicit DPL-checked instruction.
+ * The DPL specified by the guest OS for these vectors is NOT CHECKED!!
+ */
+ if ( (error_code & 3) == 2 )
{
/* This fault must be due to <INT n> instruction. */
ti = current->thread.traps + (error_code>>3);
@@ -362,7 +381,8 @@ asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
asmlinkage void math_state_restore(struct pt_regs *regs, long error_code)
{
- __asm__ __volatile__("clts");
+ /* Prevent recursion. */
+ clts();
if ( !(current->flags & PF_USEDFPU) )
{
@@ -384,53 +404,42 @@ asmlinkage void math_state_restore(struct pt_regs *regs, long error_code)
}
-/*
- * Our handling of the processor debug registers is non-trivial.
- * We do not clear them on entry and exit from the kernel. Therefore
- * it is possible to get a watchpoint trap here from inside the kernel.
- * However, the code in ./ptrace.c has ensured that the user can
- * only set watchpoints on userspace addresses. Therefore the in-kernel
- * watchpoint trap can only occur in code which is reading/writing
- * from user space. Such code must not hold kernel locks (since it
- * can equally take a page fault), therefore it is safe to call
- * force_sig_info even though that claims and releases locks.
- *
- * Code in ./signal.c ensures that the debug control register
- * is restored before we deliver any signal, and therefore that
- * user code runs with the correct debug control register even though
- * we clear it here.
- *
- * Being careful here means that we don't have to be as careful in a
- * lot of more complicated places (task switching can be a bit lazy
- * about restoring all the debug state, and ptrace doesn't have to
- * find every occurrence of the TF bit that could be saved away even
- * by user code)
- */
asmlinkage void do_debug(struct pt_regs * regs, long error_code)
{
unsigned int condition;
struct task_struct *tsk = current;
+ struct guest_trap_bounce *gtb = guest_trap_bounce+smp_processor_id();
__asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
/* Mask out spurious debug traps due to lazy DR7 setting */
- if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
- if (!tsk->thread.debugreg[7])
- goto clear_dr7;
+ if ( (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) &&
+ (tsk->thread.debugreg[7] == 0) )
+ {
+ __asm__("movl %0,%%db7" : : "r" (0));
+ return;
}
- /* Save debug status register where ptrace can see it */
- tsk->thread.debugreg[6] = condition;
+ if ( (regs->xcs & 3) == 0 )
+ {
+ /* Clear TF just for absolute sanity. */
+ regs->eflags &= ~EF_TF;
+ /*
+ * Basically, we ignore watchpoints when they trigger in
+ * the hypervisor. This may happen when a buffer is passed
+ * to us which previously had a watchpoint set on it.
+ * No need to bump EIP; the only faulting trap is an
+ * instruction breakpoint, which can't happen to us.
+ */
+ return;
+ }
- panic("trap up to OS here, pehaps\n");
+ /* Save debug status register where guest OS can peek at it */
+ tsk->thread.debugreg[6] = condition;
- /* Disable additional traps. They'll be re-enabled when
- * the signal is delivered.
- */
- clear_dr7:
- __asm__("movl %0,%%db7"
- : /* no output */
- : "r" (0));
+ gtb->flags = GTBF_TRAP_NOCODE;
+ gtb->cs = tsk->thread.traps[1].cs;
+ gtb->eip = tsk->thread.traps[1].address;
}
@@ -515,9 +524,9 @@ void __init trap_init(void)
set_trap_gate(0,&divide_error);
set_trap_gate(1,&debug);
set_intr_gate(2,&nmi);
- set_system_gate(3,&int3); /* int3-5 can be called from all */
- set_system_gate(4,&overflow);
- set_system_gate(5,&bounds);
+ set_system_gate(3,&int3); /* usable from all privilege levels */
+ set_system_gate(4,&overflow); /* usable from all privilege levels */
+ set_trap_gate(5,&bounds);
set_trap_gate(6,&invalid_op);
set_trap_gate(7,&device_not_available);
set_trap_gate(8,&double_fault);
@@ -533,27 +542,6 @@ void __init trap_init(void)
set_trap_gate(18,&machine_check);
set_trap_gate(19,&simd_coprocessor_error);
- /*
- * Cunning trick to allow arbitrary "INT n" handling.
- *
- * 1. 3 <= N <= 5 is trivial, as these are intended to be explicit.
- *
- * 2. All others, we set gate DPL == 0. Any use of "INT n" will thus
- * cause a GPF with CS:EIP pointing at the faulting instruction.
- * We can then peek at the instruction at check if it is of the
- * form "0xCD <imm8>". If so, we fake out an exception to the
- * guest OS. If the protected read page faults, we patch that up as
- * a page fault to the guest OS.
- * [NB. Of course we check the "soft DPL" to check that guest OS
- * wants to handle a particular 'n'. If not, we pass the GPF up
- * to the guest OS untouched.]
- *
- * 3. For efficiency, we may want to allow direct traps by the guest
- * OS for certain critical vectors (eg. 0x80 in Linux). These must
- * therefore not be mapped by hardware interrupts, and so we'd need
- * a static list of them, which we add to on demand.
- */
-
/* Only ring 1 can access monitor services. */
_set_gate(idt_table+HYPERVISOR_CALL_VECTOR,15,1,&hypervisor_call);
@@ -593,3 +581,69 @@ long do_fpu_taskswitch(void)
stts();
return 0;
}
+
+
+long do_set_debugreg(int reg, unsigned long value)
+{
+ int i;
+
+ switch ( reg )
+ {
+ case 0:
+ if ( value > (PAGE_OFFSET-4) ) return -EPERM;
+ __asm__ ( "movl %0, %%db0" : : "r" (value) );
+ break;
+ case 1:
+ if ( value > (PAGE_OFFSET-4) ) return -EPERM;
+ __asm__ ( "movl %0, %%db1" : : "r" (value) );
+ break;
+ case 2:
+ if ( value > (PAGE_OFFSET-4) ) return -EPERM;
+ __asm__ ( "movl %0, %%db2" : : "r" (value) );
+ break;
+ case 3:
+ if ( value > (PAGE_OFFSET-4) ) return -EPERM;
+ __asm__ ( "movl %0, %%db3" : : "r" (value) );
+ break;
+ case 6:
+ /*
+ * DR6: Bits 4-11,16-31 reserved (set to 1).
+ * Bit 12 reserved (set to 0).
+ */
+ value &= 0xffffefff; /* reserved bits => 0 */
+ value |= 0xffff0ff0; /* reserved bits => 1 */
+ __asm__ ( "movl %0, %%db6" : : "r" (value) );
+ break;
+ case 7:
+ /*
+ * DR7: Bit 10 reserved (set to 1).
+ * Bits 11-12,14-15 reserved (set to 0).
+ * Privileged bits:
+ * GD (bit 13): must be 0.
+ * R/Wn (bits 16-17,20-21,24-25,28-29): mustn't be 10.
+ * LENn (bits 18-19,22-23,26-27,30-31): mustn't be 10.
+ */
+ /* DR7 == 0 => debugging disabled for this domain. */
+ if ( value != 0 )
+ {
+ value &= 0xffff27ff; /* reserved bits => 0 */
+ value |= 0x00000400; /* reserved bits => 1 */
+ if ( (value & (1<<13)) != 0 ) return -EPERM;
+ for ( i = 0; i < 16; i += 2 )
+ if ( ((value >> (i+16)) & 3) == 2 ) return -EPERM;
+ }
+ __asm__ ( "movl %0, %%db7" : : "r" (value) );
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ current->thread.debugreg[reg] = value;
+ return 0;
+}
+
+unsigned long do_get_debugreg(int reg)
+{
+ if ( (reg < 0) || (reg > 7) ) return -EINVAL;
+ return current->thread.debugreg[reg];
+}
diff --git a/xen-2.4.16/include/hypervisor-ifs/hypervisor-if.h b/xen-2.4.16/include/hypervisor-ifs/hypervisor-if.h
index 2491557325..4f4d1a2d23 100644
--- a/xen-2.4.16/include/hypervisor-ifs/hypervisor-if.h
+++ b/xen-2.4.16/include/hypervisor-ifs/hypervisor-if.h
@@ -40,6 +40,8 @@ typedef struct
#define __HYPERVISOR_exit 8
#define __HYPERVISOR_dom0_op 9
#define __HYPERVISOR_network_op 10
+#define __HYPERVISOR_set_debugreg 11
+#define __HYPERVISOR_get_debugreg 12
#define TRAP_INSTR "int $0x82"
diff --git a/xenolinux-2.4.16-sparse/arch/xeno/kernel/process.c b/xenolinux-2.4.16-sparse/arch/xeno/kernel/process.c
index e4c236bf98..9e26f3d65a 100644
--- a/xenolinux-2.4.16-sparse/arch/xeno/kernel/process.c
+++ b/xenolinux-2.4.16-sparse/arch/xeno/kernel/process.c
@@ -187,6 +187,7 @@ void flush_thread(void)
struct task_struct *tsk = current;
memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8);
+
/*
* Forget coprocessor state..
*/
@@ -307,14 +308,6 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
}
/*
- * This special macro can be used to load a debugging register
- */
-#define loaddebug(thread,register) \
- __asm__("movl %0,%%db" #register \
- : /* no output */ \
- :"r" (thread->debugreg[register]))
-
-/*
* switch_to(x,yn) should switch tasks from x to y.
*
* We fsave/fwait so that an exception goes off at the right time
@@ -359,20 +352,19 @@ void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
loadsegment(fs, next->fs);
loadsegment(gs, next->gs);
-#if 0
/*
* Now maybe reload the debug registers
*/
- if (next->debugreg[7]){
- loaddebug(next, 0);
- loaddebug(next, 1);
- loaddebug(next, 2);
- loaddebug(next, 3);
+ if ( next->debugreg[7] != 0 )
+ {
+ HYPERVISOR_set_debugreg(0, next->debugreg[0]);
+ HYPERVISOR_set_debugreg(1, next->debugreg[1]);
+ HYPERVISOR_set_debugreg(2, next->debugreg[2]);
+ HYPERVISOR_set_debugreg(3, next->debugreg[3]);
/* no 4 and 5 */
- loaddebug(next, 6);
- loaddebug(next, 7);
+ HYPERVISOR_set_debugreg(6, next->debugreg[6]);
+ HYPERVISOR_set_debugreg(7, next->debugreg[7]);
}
-#endif
}
asmlinkage int sys_fork(struct pt_regs regs)
diff --git a/xenolinux-2.4.16-sparse/arch/xeno/kernel/signal.c b/xenolinux-2.4.16-sparse/arch/xeno/kernel/signal.c
index c0f43e6342..a23cec1dea 100644
--- a/xenolinux-2.4.16-sparse/arch/xeno/kernel/signal.c
+++ b/xenolinux-2.4.16-sparse/arch/xeno/kernel/signal.c
@@ -693,6 +693,14 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
}
}
+ /* Reenable any watchpoints before delivering the
+ * signal to user space. The processor register will
+ * have been cleared if the watchpoint triggered
+ * inside the kernel.
+ */
+ if ( current->thread.debugreg[7] != 0 )
+ HYPERVISOR_set_debugreg(7, current->thread.debugreg[7]);
+
/* Whee! Actually deliver the signal. */
handle_signal(signr, ka, &info, oldset, regs);
return 1;
diff --git a/xenolinux-2.4.16-sparse/arch/xeno/kernel/traps.c b/xenolinux-2.4.16-sparse/arch/xeno/kernel/traps.c
index 6e8f347420..2a546b49d5 100644
--- a/xenolinux-2.4.16-sparse/arch/xeno/kernel/traps.c
+++ b/xenolinux-2.4.16-sparse/arch/xeno/kernel/traps.c
@@ -324,11 +324,60 @@ gp_in_kernel:
asmlinkage void do_debug(struct pt_regs * regs, long error_code)
{
- /*
- * We don't mess with breakpoints, so the only way this exception
- * type can occur is through single-step mode.
+ unsigned int condition;
+ struct task_struct *tsk = current;
+ siginfo_t info;
+
+ condition = HYPERVISOR_get_debugreg(6);
+
+ /* Mask out spurious debug traps due to lazy DR7 setting */
+ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
+ if (!tsk->thread.debugreg[7])
+ goto clear_dr7;
+ }
+
+ /* Save debug status register where ptrace can see it */
+ tsk->thread.debugreg[6] = condition;
+
+ /* Mask out spurious TF errors due to lazy TF clearing */
+ if (condition & DR_STEP) {
+ /*
+ * The TF error should be masked out only if the current
+ * process is not traced and if the TRAP flag has been set
+ * previously by a tracing process (condition detected by
+ * the PT_DTRACE flag); remember that the i386 TRAP flag
+ * can be modified by the process itself in user mode,
+ * allowing programs to debug themselves without the ptrace()
+ * interface.
+ */
+ if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
+ goto clear_TF;
+ }
+
+ /* Ok, finally something we can handle */
+ tsk->thread.trap_no = 1;
+ tsk->thread.error_code = error_code;
+ info.si_signo = SIGTRAP;
+ info.si_errno = 0;
+ info.si_code = TRAP_BRKPT;
+
+ /* If this is a kernel mode trap, save the user PC on entry to
+ * the kernel, that's what the debugger can make sense of.
*/
+ info.si_addr = ((regs->xcs & 3) == 0) ? (void *)tsk->thread.eip :
+ (void *)regs->eip;
+ force_sig_info(SIGTRAP, &info, tsk);
+
+ /* Disable additional traps. They'll be re-enabled when
+ * the signal is delivered.
+ */
+ clear_dr7:
+ HYPERVISOR_set_debugreg(7, 0);
+ return;
+
+ clear_TF:
regs->eflags &= ~TF_MASK;
+ return;
}
diff --git a/xenolinux-2.4.16-sparse/include/asm-xeno/hypervisor.h b/xenolinux-2.4.16-sparse/include/asm-xeno/hypervisor.h
index 522f124e86..f46bfe4c44 100644
--- a/xenolinux-2.4.16-sparse/include/asm-xeno/hypervisor.h
+++ b/xenolinux-2.4.16-sparse/include/asm-xeno/hypervisor.h
@@ -163,4 +163,26 @@ static inline int HYPERVISOR_network_op(void *network_op)
return ret;
}
+static inline int HYPERVISOR_set_debugreg(int reg, unsigned long value)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_set_debugreg),
+ "b" (reg), "c" (value) );
+
+ return ret;
+}
+
+static inline unsigned long HYPERVISOR_get_debugreg(int reg)
+{
+ unsigned long ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_get_debugreg),
+ "b" (reg) );
+
+ return ret;
+}
+
#endif /* __HYPERVISOR_H__ */