(unsigned long *)regs->rsp :
(unsigned long *)n->arch.kernel_sp;
- /* Set the kernel-mode indicator byte at the top of RFLAGS. */
- ((char *)regs->rflags)[7] = !!(n->arch.flags & TF_kernel_mode);
-
if ( !(n->arch.flags & TF_kernel_mode) )
toggle_guest_mode(n);
+ else
+ regs->cs &= ~3;
if ( put_user(regs->ss, rsp- 1) |
put_user(regs->rsp, rsp- 2) |
toggle_guest_mode(ed);
regs->rip = stu.rip;
- regs->cs = stu.cs;
+ regs->cs = stu.cs | 3; /* force guest privilege */
regs->rflags = stu.rflags;
regs->rsp = stu.rsp;
- regs->ss = stu.ss;
+ regs->ss = stu.ss | 3; /* force guest privilege */
if ( !(stu.flags & ECF_IN_SYSCALL) )
{
int nr = smp_processor_id();
struct tss_struct *t = &init_tss[nr];
- /* We need to do this check as we load and use SS on guest's behalf. */
- if ( (ss & 3) == 0 )
+ if ( (ss & 3) != 1 )
return -EPERM;
current->arch.kernel_ss = ss;
if ( (b & _SEGMENT_G) )
limit <<= 12;
- if ( (b & (_SEGMENT_CODE | _SEGMENT_EC)) == _SEGMENT_EC )
- {
- /*
- * Grows-down limit check.
- * NB. limit == 0xFFFFF provides no access (if G=1).
- * limit == 0x00000 provides 4GB-4kB access (if G=1).
- */
- if ( (base + limit) > base )
- {
- limit = -(base & PAGE_MASK);
- goto truncate;
- }
- }
- else
+ switch ( b & (_SEGMENT_CODE | _SEGMENT_EC) )
{
+ case 0: /* Data segment, grows-up */
/*
* Grows-up limit check.
* NB. limit == 0xFFFFF provides 4GB access (if G=1).
d->a &= ~0x0ffff; d->a |= limit & 0x0ffff;
d->b &= ~0xf0000; d->b |= limit & 0xf0000;
}
+ goto good;
+ case _SEGMENT_EC: /* Data segment, grows-down */
+ /*
+ * Grows-down limit check.
+ * NB. limit == 0xFFFFF provides no access (if G=1).
+ * limit == 0x00000 provides 4GB-4kB access (if G=1).
+ */
+ if ( (base + limit) > base )
+ {
+ limit = -(base & PAGE_MASK);
+ goto truncate;
+ }
+ goto good;
+ case _SEGMENT_CODE: /* Code segment, non-conforming */
+ goto good;
+ case _SEGMENT_CODE|_SEGMENT_EC: /* Code segment, conforming */
+ goto bad;
}
good:
/* %rdx: trap_bounce, %rbx: struct exec_domain */
/* On return only %rbx is guaranteed non-clobbered. */
create_bounce_frame:
- /* Push new frame at existing %rsp if already in guest-OS mode. */
- movq XREGS_rsp+8(%rsp),%rsi
testb $TF_kernel_mode,EDOMAIN_thread_flags(%rbx)
- /* Set kernel-mode indicator byte (RFLAGS[63:56]). */
- setnz XREGS_eflags+15(%rsp)
jnz 1f
/* Push new frame at registered guest-OS stack base. */
- /* Then call to C: toggle_guest_mode(current) */
movq EDOMAIN_kernel_sp(%rbx),%rsi
- movq %rbx,%rdi
pushq %rdx
+ movq %rbx,%rdi
call SYMBOL_NAME(toggle_guest_mode)
popq %rdx
-1: movq $HYPERVISOR_VIRT_START,%rax
+ jmp 2f
+1: /* In kernel context already: push new frame at existing %rsp. */
+ movq XREGS_rsp+8(%rsp),%rsi
+ andb $0xfc,XREGS_cs+8(%rsp) # Indicate kernel context to guest.
+2: movq $HYPERVISOR_VIRT_START,%rax
cmpq %rax,%rsi
jb 1f # In +ve address space? Then okay.
movq $HYPERVISOR_VIRT_END+60,%rax
if ( (b & _SEGMENT_DPL) != 3 )
goto bad;
- /* Any code or data segment is okay. No base/limit checking. */
+ /* Most code and data segments are okay. No base/limit checking. */
if ( (b & _SEGMENT_S) )
+ {
+ /* Disallow conforming code segments. I'm not sure they're safe. */
+ if ( (b & (_SEGMENT_CODE|_SEGMENT_EC)) == (_SEGMENT_CODE|_SEGMENT_EC) )
+ goto bad;
goto good;
+ }
/* Invalid type 0 is harmless. It is used for 2nd half of a call gate. */
if ( (b & _SEGMENT_TYPE) == 0x000 )
#define load_TR(n) __asm__ __volatile__ ("ltr %%ax" : : "a" (__TSS(n)<<3) )
+#if defined(__x86_64__)
+#define GUEST_KERNEL_RPL 3
+#elif defined(__i386__)
+#define GUEST_KERNEL_RPL 1
+#endif
+
/*
- * Guest OS must provide its own code selectors, or use the one we provide. The
- * RPL must be 1, as we only create bounce frames to ring 1. Any LDT selector
- * value is okay. Note that checking only the RPL is insufficient: if the
- * selector is poked into an interrupt, trap or call gate then the RPL is
- * ignored when the gate is accessed.
+ * Guest OS must provide its own code selectors, or use the one we provide. Any
+ * LDT selector value is okay. Note that checking only the RPL is insufficient:
+ * if the selector is poked into an interrupt, trap or call gate then the RPL
+ * is ignored when the gate is accessed.
*/
#define VALID_SEL(_s) \
(((((_s)>>3) < FIRST_RESERVED_GDT_ENTRY) || \
(((_s)>>3) > LAST_RESERVED_GDT_ENTRY) || \
((_s)&4)) && \
- (((_s)&3) == 1))
+ (((_s)&3) == GUEST_KERNEL_RPL))
#define VALID_CODESEL(_s) ((_s) == FLAT_KERNEL_CS || VALID_SEL(_s))
/* These are bitmasks for the high 32 bits of a descriptor table entry. */